Anton Pilyak
Anton Pilyak

Reputation: 1140

Is there any way to check if a template class has a nested class definition (or a typedef) in C++14?

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

Answers (1)

cigien
cigien

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

Related Questions