Reputation: 1140
I have the following structures defined:
struct NoRelationship {};
struct OneToMany {};
struct Interdependent {};
template <typename RelationType>
struct SignatureGenerator
{
using type = std::function<void()>;
};
template <>
struct SignatureGenerator<Interdependent>
{
using type = std::function<void()>;
using extra_type = std::function<void()>;
};
I need to implement a SFINAE check which would determine if a class has the "extra_type" definition. I have checked this and this topics, but still can't find a working solution. I have tried the following code from the latter topic:
template <typename T>
class has_extra_type
{
typedef char yes;
struct no {char x[2];};
template<typename C> static yes test(decltype(&C::extra_type));
template<typename C> static no test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof (char)};
};
But this doesn't work, because of the 'missing 'typename' prior to dependent type name' error. That is what the compiler tells if I comment out the general specification:
// template<typename C> static no test(...);
error: no matching function for call to 'test' enum { value = sizeof(test(0)) == sizeof (char)};
note: candidate template ignored: substitution failure [with C = SignatureGenerator]: missing 'typename' prior to dependent type name 'SignatureGenerator::extra_type' template static yes test(decltype(&C::extra_type));
Any ideas on how to bypass this?
*Update: here is how I use the checks:
int main() {
std::cout << has_extra_type<SignatureGenerator<OneToMany>>::value <<std::endl;
std::cout << has_extra_type<SignatureGenerator<Interdependent>>::value <<std::endl;
return 0;
}
It gives 0 for both of the classes, while I expected the 'extra_type' to be detected in the second case.
Upvotes: 0
Views: 593
Reputation: 60422
For your yes
overload, you are using:
template<typename C> static yes test(decltype(&C::extra_type)); // incorrect for types
However, the decltype
and &
is only needed because the example that you were looking at was checking for the existence of a member function. But extra_type
is a type, and so you can't take its address, and so that expression is always ill-formed, and the overload is never chosen.
Since you're checking for the existence of a member type alias, you can simply do:
template<typename C> static yes test(typename C::extra_type*);
Here's a demo.
Upvotes: 2