Я смотрел выступление Уолтера Брауна на Cppcon14 о современном программировании шаблонов ( часть I , часть II ), где он представил свою void_tтехнику SFINAE.
Пример:
дан простой шаблон переменной, который оценивает, правильно voidли сформированы все аргументы шаблона:
template< class ... > using void_t = void;
и следующая черта, которая проверяет существование переменной- члена, называемой member :
template< class , class = void >
struct has_member : std::false_type
{ };
// specialized as has_member< T , void > or discarded (sfinae)
template< class T >
struct has_member< T , void_t< decltype( T::member ) > > : std::true_type
{ };
Я пытался понять, почему и как это работает. Поэтому крошечный пример:
class A {
public:
int member;
};
class B {
};
static_assert( has_member< A >::value , "A" );
static_assert( has_member< B >::value , "B" );
1. has_member< A >
has_member< A , void_t< decltype( A::member ) > >A::memberсуществуютdecltype( A::member )хорошо сформированvoid_t<>действителен и оцениваетvoid
has_member< A , void >и поэтому он выбирает специализированный шаблонhas_member< T , void >и оцениваетtrue_type
2. has_member< B >
has_member< B , void_t< decltype( B::member ) > >B::memberне существуетdecltype( B::member )плохо сформирован и терпит неудачу (sfinae)has_member< B , expression-sfinae >так что этот шаблон отбрасывается
- компилятор находит
has_member< B , class = void >с void в качестве аргумента по умолчанию has_member< B >оцениваетfalse_type
Вопросы:
1. Правильно ли я понимаю это?
2. Уолтер Браун заявляет, что аргумент по умолчанию должен быть того же типа, который используется void_tдля его работы. Это почему? (Я не понимаю, почему эти типы должны совпадать, разве не какой-либо тип по умолчанию работает?)
has_member< T , class = void >дефолте void. Предполагая, что эта черта будет использоваться только с 1 аргументом шаблона в любое время, тогда аргумент по умолчанию может быть любого типа?
template <class, class = void>на template <class, class = void_t<>>. Так что теперь мы можем делать все, что захотим, с void_tреализацией шаблона псевдонима :)
has_member<A,int>::value. Тогда частичная специализация, которая оценивается как,has_member<A,void>не может соответствовать. Следовательно, он должен бытьhas_member<A,void>::valueили, с синтаксическим сахаром, аргументом по умолчанию типаvoid.