Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking if class T has member type Member with void_t

So here's the code:

template<typename, typename, typename = void>
struct has_member_type : false_type {};

template<typename T, typename Member>
struct has_member_type<T, Member, void_t<typename T::Member>> : true_type {};

struct foo { using bar = int; };

int main()
{
    std::cout << has_member_type<foo, typename foo::bar>::value;
}

I'm trying to check whether foo has a bar type member. It works fine if the implementation doesn't specify the type member's name, but that way the name is hardcoded into the implementation, which doesn't work for me.

The question said to be duplicate doesn't come close to answering my question. As I explained in the paragraph above, it's fine when the type is hardcoded into the implementation, but I can't get it to work when I specify the type from outside (that's the specific problem). The code compiles fine, but produces wrong results.

like image 676
DeiDei Avatar asked Feb 08 '23 23:02

DeiDei


1 Answers

Your code doesn't work because typename foo::bar just directly resolves to int, rather than passing in some construct you can use for SFINAE.

A possible solution is to make an alias template which will tell you what the type of T::bar is, then pass that into your checker. This is what std::experimental::is_detected does. Here is a simplified version which is close to what you had already*:

template<typename, template <typename> class, typename = void>
struct is_detected : false_type {};

template<typename T, template <typename> class Op>
struct is_detected<T, Op, void_t<Op<T>>> : true_type {};

Then you write your alias template which you want to detect:

template <typename T> using bar_t = typename T::bar;

And usage looks like this:

is_detected <foo, bar_t>::value

*: I kept the template parameters the same way around as in your sample code so that you can easily compare. Flipping them around so that you can make the operator arguments variadic is better in a more generic context. It would also make it easier to migrate to std::experimental::is_detected when available for you.

like image 123
TartanLlama Avatar answered Feb 16 '23 04:02

TartanLlama