0

I am trying to write a type trait to detect if a type has a T::type of certain type. I am using code from this answer. For reference this is the part of the code I am using:

// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf.
template <typename...>
using void_t = void;

// Primary template handles all types not supporting the operation.
template <typename, template <typename> class, typename = void_t<>>
struct detect : std::false_type {};

// Specialization recognizes/validates only types supporting the archetype.
template <typename T, template <typename> class Op>
struct detect<T, Op, void_t<Op<T>>> : std::true_type {};

I started simple with a trait to detect the T::type :

template <typename T>
using has_type_t = typename T::type;

template <typename T>
using has_type = detect<T, has_type_t>;

This works as expected, but when I ask for the actual type of T::type also I get errors that I do not understand:

template <typename X>
struct has_X_type_helper {
    template <typename T>
    using type = typename std::enable_if_t<std::is_same_v< typename T::type, X>,int>;
};

template <typename T,typename X>
using has_X_type = detect<T,has_X_type_helper<X>::type>;

GCC:

<source>:49:55: error: type/value mismatch at argument 2 in template parameter list for 'template<class, template<class> class<template-parameter-1-2>, class> struct detect'
   49 | using has_X_type = detect<T,has_X_type_helper<X>::type>;
      |                                                       ^
<source>:49:55: note:   expected a class template, got 'has_X_type_helper<X>::type'

and Clang is even more confusing for me

<source>:49:29: error: template argument for template template parameter must be a class template or type alias template
using has_X_type = detect<T,has_X_type_helper<X>::type>;
                            ^

Is has_X_type_helper<X>::type not a type alias template ? What is wrong in my code?

@ godbolt

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185

1 Answers1

1

You need to indicate that the nested thing is a template:

template <typename T, typename X>
using has_X_type = detect<T, has_X_type_helper<X>::template type>;
//                                               ~~~~~~~~~^
Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
  • i think this is the new top in my list of most unintuitve syntax. Is it needed because `has_X_type_helper` is a template? or because `has_X_type_helper::type` is a template? I still find it a bit confusing, because `has_X_type_helper` is just a type and `has_X_type_helper::type` is a template just as `has_type_t` is one – 463035818_is_not_an_ai Jun 09 '20 at 08:41
  • ah I think I got it. `has_X_type_helper` could have specializations so I need to assure the compiler that `type` is a template – 463035818_is_not_an_ai Jun 09 '20 at 08:44
  • @idclev463035818 Yes, it's the same story as with `typename`. Otherwise, the compiler assumes it's a value like `std::is_const::value`, hece it reports `'type/value mismatch'` – Piotr Skotnicki Jun 09 '20 at 09:09