Я спостерігав, як Уолтер Браун розмовляв на 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
.