Oglądałem wykład Waltera Browna na Cppcon14 o nowoczesnym programowaniu szablonów ( część I , część II ), gdzie przedstawił swoją void_ttechnikę SFINAE.
Przykład:
biorąc pod uwagę prosty szablon zmiennej, który ocenia, voidczy wszystkie argumenty szablonu są poprawnie sformułowane:
template< class ... > using void_t = void;
oraz następującą cechę, która sprawdza istnienie zmiennej składowej o nazwie 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
{ };
Próbowałem zrozumieć, dlaczego i jak to działa. Dlatego mały przykład:
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::memberistniejedecltype( A::member )jest dobrze uformowanyvoid_t<>jest ważny i jest oceniany dovoid
has_member< A , void >i dlatego wybiera specjalistyczny szablonhas_member< T , void >i ocenia dotrue_type
2. has_member< B >
has_member< B , void_t< decltype( B::member ) > >B::membernie istniejedecltype( B::member )jest źle ukształtowany i cicho zawodzi (sfinae)has_member< B , expression-sfinae >więc ten szablon jest odrzucany
- kompilator znajdzie
has_member< B , class = void >argument void jako domyślny has_member< B >ocenia dofalse_type
Pytania:
1. Czy moje rozumienie tego jest prawidłowe?
2. Walter Brown stwierdza, że domyślny argument musi być dokładnie tego samego typu, co używany w programie void_t, aby działał. Dlaczego? (Nie rozumiem, dlaczego te typy muszą pasować, czy żaden domyślny typ nie spełnia tego zadania?)
has_member< T , class = void >wpadania w zwłokę void. Zakładając, że ta cecha będzie używana tylko z 1 argumentem szablonu w dowolnym momencie, to domyślny argument może być dowolnego typu?
template <class, class = void>na template <class, class = void_t<>>. Więc teraz możemy robić, co chcemy, z void_timplementacją szablonu aliasu :)
has_member<A,int>::value. Wtedy częściowa specjalizacja, którejhas_member<A,void>wynikiem jest ocena, nie może być zgodna. Dlatego musi to byćhas_member<A,void>::valuelub, w przypadku cukru składniowego, domyślny argument typuvoid.