0

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.

cigien
  • 50,328
  • 7
  • 37
  • 78
Anton Pilyak
  • 822
  • 10
  • 28
  • I'm not sure what the issue is. Can you show how you're using `has_extra_type`? Maybe the issue lies there. – cigien Mar 08 '21 at 02:32
  • No, I don' think there is an issue there, please, see the updated question. – Anton Pilyak Mar 08 '21 at 02:41
  • 2
    You might be interested by: [`std::experimental::is_detected`](https://en.cppreference.com/w/cpp/experimental/is_detected). – Jarod42 Mar 08 '21 at 13:28

1 Answers1

1

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.

cigien
  • 50,328
  • 7
  • 37
  • 78