Saya menyaksikan pembicaraan Walter Brown di Cppcon14 tentang pemrograman template modern ( Bagian I , Bagian II ) di mana ia mempresentasikan void_t
teknik SFINAE- nya .
Contoh:
Diberi templat variabel sederhana yang mengevaluasi void
jika semua argumen templat terbentuk dengan baik:
template< class ... > using void_t = void;
dan sifat berikut yang memeriksa keberadaan variabel anggota yang disebut anggota :
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
{ };
Saya mencoba memahami mengapa dan bagaimana ini bekerja. Karena itu contoh kecil:
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
adadecltype( A::member )
terbentuk dengan baikvoid_t<>
valid dan dievaluasi untukvoid
has_member< A , void >
dan karena itu memilih templat khusushas_member< T , void >
dan mengevaluasi ketrue_type
2. has_member< B >
has_member< B , void_t< decltype( B::member ) > >
B::member
tidak adadecltype( B::member )
berbentuk buruk dan gagal diam-diam (sfinae)has_member< B , expression-sfinae >
jadi templat ini dibuang
- kompiler ditemukan
has_member< B , class = void >
dengan void sebagai argumen default has_member< B >
mengevaluasi kefalse_type
Pertanyaan:
1. Apakah pemahaman saya tentang ini benar?
2. Walter Brown menyatakan bahwa argumen default haruslah tipe yang sama persis seperti yang digunakan void_t
agar bisa berfungsi. Mengapa demikian? (Saya tidak mengerti mengapa jenis ini harus cocok, bukankah sembarang jenis standar berfungsi?)
has_member< T , class = void >
defaulting void
. Dengan asumsi sifat ini hanya akan digunakan dengan 1 argumen templat kapan saja, maka argumen default dapat berupa jenis apa saja?
template <class, class = void>
menjadi template <class, class = void_t<>>
. Jadi sekarang kita bebas untuk melakukan apa pun yang kita inginkan dengan void_t
implementasi template alias :)
has_member<A,int>::value
. Kemudian, spesialisasi parsial yang mengevaluasihas_member<A,void>
tidak dapat cocok. Oleh karena itu, perluhas_member<A,void>::value
, atau, dengan gula sintaksis, argumen tipe defaultvoid
.