dimanche 28 décembre 2014

Does SFINAE not apply here?

I was writing something to use SFINAE to not generate a function under certain conditions. When I use the meta code directly it works as expected, but when I use the code indirectly through another class, it fails to work as expected.


I thought that this was a VC++ thing, but looks like g++ also has this, so I'm wondering if there's some reason that SFINAE isn't being applied to this case.


The code is simple. If the class used isn't the base class of a "collection class", then don't generate the function.



#include <algorithm>
#include <type_traits>

#define USE_DIRECT 0
#define ENABLE 1

class A{};
class B{};
class C{};
class D{};
class collection1 : A, B, C {};
class collection2 : D {};

#if USE_DIRECT
template<typename X>
typename std::enable_if<std::is_base_of<X, collection1>::value, X>::type fn(X x)
{
return X();
}

# if ENABLE
template<typename X>
typename std::enable_if<std::is_base_of<X, collection2>::value, X>::type fn(X x)
{
return X();
}
# endif

#else // USE_DIRECT

template<typename X, typename COLLECTION>
struct enable_if_is_base_of
{
static const int value = std::is_base_of<X, COLLECTION>::value;
typedef typename std::enable_if<value, X>::type type;
};

template<typename X>
typename enable_if_is_base_of<X, collection1>::type fn(X x)
{
return X();
}

# if ENABLE
template<typename X>
typename enable_if_is_base_of<X, collection2>::type fn(X x)
{
return X();
}
# endif
#endif // USE_DIRECT

int main()
{
fn(A());
fn(B());
fn(C());
fn(D());

return 0;
}


If I set USE_DIRECT to 1 and ENABLE to 0, then it fails to compile as there is no function fn that takes a parameter D. Setting ENABLE to 1 will stop that error from occurring.


However, if I set USE_DIRECT to 0 and ENABLE to 0, it will fail with different error messages but for the same case, there is no fn that takes parameter D. Setting ENABLE to 1 however will cause a failure for all 4 function calls.


For your convience, here is the code in an online compiler: http://goo.gl/CQcXHr


Can someone explain what is happening here and why?


This looks like it may be related to Alias templates used in SFINAE lead to a hard error, but no one has answered that either.


Aucun commentaire:

Enregistrer un commentaire