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