C++14如何检测类中存在指定嵌套类型?现有实现为何失效?
错误原因
- 模板偏特化的匹配要求参数类型完全一致。你定义的主模板第二个模板参数默认值为
void,当直接写has_some_type<X>时,实际实例化的模板是has_some_type<X, void>。 - 嵌套类型检测的偏特化第二个参数是
typename C::some_type,对X来说该类型是int,和void不匹配,因此偏特化不会被选中,最终只会匹配到继承std::false_type的主模板,导致断言失败。 - 你写的成员函数检测代码属于碰巧可用,并非通用正确实现:因为示例中
some_function返回值是void,decltype推导的结果刚好和主模板默认的void匹配才生效。如果把函数返回值改为int,该检测逻辑同样会失败。
正确实现
C14中可以自行实现void_t(C17已纳入标准库),它的作用是将任意传入的类型列表统一映射为void类型,保证偏特化的第二个参数和主模板的默认void匹配,触发SFINAE机制完成检测。
修正后的嵌套类型检测代码如下:
#include <type_traits> // C++14 手动实现void_t template <typename...> using void_t = void; struct X { using some_type = int; }; struct Y {}; template <typename T, typename = void> struct has_some_type : std::false_type {}; // 用void_t包裹要检测的嵌套类型,保证第二个参数为void template <typename C> struct has_some_type<C, void_t<typename C::some_type>> : std::true_type {}; static_assert(has_some_type<X>::value); // 检测成功 static_assert(!has_some_type<Y>::value); // 检测成功
如果要实现通用的、不依赖返回值的成员函数检测,同样需要使用void_t包裹检测表达式:
template <typename T, typename = void> struct has_some_function : std::false_type {}; template <typename C> struct has_some_function<C, void_t<decltype(std::declval<C>().some_function())>> : std::true_type {};
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

