Tôi đã xem cuộc nói chuyện của Walter Brown tại Cppcon14 về lập trình mẫu hiện đại ( Phần I , Phần II ) nơi anh ấy trình bày void_t
kỹ thuật SFINAE của mình .
Ví dụ:
Đưa ra một mẫu biến đơn giản để ước tính void
nếu tất cả các đối số mẫu được hình thành tốt:
template< class ... > using void_t = void;
và đặc điểm sau đây kiểm tra sự tồn tại của biến thành viên được gọi là thành viên :
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
{ };
Tôi đã cố gắng để hiểu tại sao và làm thế nào điều này hoạt động. Vì vậy, một ví dụ nhỏ:
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
tồn tạidecltype( A::member )
được hình thành tốtvoid_t<>
là hợp lệ và đánh giávoid
has_member< A , void >
và do đó nó chọn mẫu chuyên dụnghas_member< T , void >
và đánh giátrue_type
2. has_member< B >
has_member< B , void_t< decltype( B::member ) > >
B::member
không tồn tạidecltype( B::member )
không thành công và thất bại âm thầm (sfinae)has_member< B , expression-sfinae >
vì vậy mẫu này bị loại bỏ
- trình biên dịch tìm thấy
has_member< B , class = void >
với void là đối số mặc định has_member< B >
đánh giáfalse_type
Câu hỏi:
1. Sự hiểu biết của tôi về điều này có đúng không?
2. Walter Brown tuyên bố rằng đối số mặc định phải là loại chính xác giống như đối số được sử dụng void_t
để nó hoạt động. Tại sao vậy? (Tôi không thấy lý do tại sao các loại này cần phải khớp, không phải bất kỳ loại mặc định nào thực hiện công việc?)
has_member< T , class = void >
mặc định void
. Giả sử đặc điểm này sẽ chỉ được sử dụng với 1 đối số mẫu bất cứ lúc nào, thì đối số mặc định có thể là loại nào?
template <class, class = void>
thành template <class, class = void_t<>>
. Vì vậy, bây giờ chúng tôi có thể tự do làm bất cứ điều gì chúng tôi muốn với void_t
việc triển khai mẫu bí danh :)
has_member<A,int>::value
. Sau đó, chuyên môn hóa một phần mà đánh giá làhas_member<A,void>
không thể phù hợp. Do đó, nó cần phảihas_member<A,void>::value
, hoặc, với đường cú pháp, một đối số mặc định của loạivoid
.