Я смотрел, как Уолтер Браун говорил на 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
для его работы. Почему это? (Я не понимаю, почему эти типы должны соответствовать, не только ли тип по умолчанию выполняет задание?)