通过创建一个模板元函数来检查一个类是否有一个特定的成员。以下是一个例子:
cpp
#include <type_traits>
template<typename T, typename = void>
struct has_type_member : std::false_type {};
template<typename T>
struct has_type_member<T,
std::void_t<typename T::type>> : std::true_type {};
struct Test {
using type = double;
};
int main() {
static_assert(has_type_member<Test>::value, "Test::type exists");
static_assert(!has_type_member<int>::value, "int::type doesn't exist");
return 0;
}
在这个例子中,has_type_member
是一个模板元函数,它检查其模板参数 T
是否有一个名为 type
的成员。它首先假设 T
没有 type
成员,然后通过模板特化来检查 T
是否真的有 type
成员。
如果 T::type
存在,那么 std::void_t<typename T::type>
就是 void
,所以 has_type_member<T, std::void_t<typename T::type>>
就是 has_type_member<T, void>
,这匹配了模板特化,所以 has_type_member<T>::value
是 true
。
如果 T::type
不存在,那么 std::void_t<typename T::type>
就会导致一个编译错误,但是由于模板参数的 SFINAE(Substitution Failure Is Not An Error)特性,这个错误会被忽略,然后编译器就会选择 has_type_member<T, void>
的主模板,所以 has_type_member<T>::value
是 false
。
所以,你可以使用 has_type_member<T>::value
来检查一个类型 T
是否有一个 type
成员。
扩展:
SFINAE 是 "Substitution Failure Is Not An Error" 的缩写,它是 C++ 模板元编程中的一个重要概念。
在模板实例化过程中,编译器会尝试用具体的类型替换模板参数。这个替换过程有时可能会失败,例如当我们尝试调用一个不存在的函数或访问一个不存在的成员。在大多数情况下,这种替换失败将导致编译错误。但在某些情况下,C++ 标准允许这种替换失败,并且不会产生编译错误,这就是 SFINAE 的原理。