Как проверить на typename в классе? - PullRequest
0 голосов
/ 08 февраля 2019

В шаблоне класса Foo Я хочу проверить, предоставляет ли параметр шаблона тип с именем Bar.

struct TypeA {using Bar = int;};
struct TypeB {};
template<class T>Foo{};

void main(){
  Foo<TypeA> a; // I want this to compile
  Foo<TypeB> b; // I want this to not compile, but print a nice message.
}

Поскольку я хочу объединить это с другими свойствами, я хочу hasBarmetafunction.Поэтому я могу объединить логические значения и затем использовать std::enable_if.

Я пытался понять и использовать SFINAE, но не смог:

template<class T, class Enable = void>struct hasBar : std::false_type {};

template<class T>
struct hasBar<T,decltype(std::declval<T::Bar>(),void())> : std::true_type {};

hasBar<TypeA>::value всегда ложно.

Как правильно определить hasBar?

Или есть какой-то лучший подход, чем using, к наличию бара?

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

Самый простой способ - использовать зависимый тип в качестве значения по умолчанию для безымянного параметра шаблона.Примерно так:

struct with_bar { using Bar = int; };
struct without_bar { };

template <typename T, typename = typename T::Bar>
struct bar_detector { };

int main() {
  bar_detector<with_bar>();
  bar_detector<without_bar>(); // won' compile
}

Это дает довольно полезное сообщение об ошибке (g++ 7.3.0): error: no type named ‘Bar’ in ‘struct without_bar’.

0 голосов
/ 08 февраля 2019

Вы должны добавить typename перед T::Bar, чтобы указать, что это имя вложенного типа, то есть

template<class T>
struct hasBar<T,decltype(std::declval<typename T::Bar>(),void())> : std::true_type {};

LIVE

Кстати: вы можете использоватьstd::void_t, чтобы упростить его.например,

template< class, class = std::void_t<> >
struct hasBar : std::false_type { };

template< class T >
struct hasBar<T, std::void_t<typename T::Bar>> : std::true_type { };
...