我尝试使用以下方法实现is_union_or_class
,首先没有void_t
:
#include <type_traits>
namespace detail {
template <class T>
struct is_union_or_class_helper1 : public std::false_type { };
template <class T>
struct is_union_or_class_helper1<char T::*> : public std::true_type { };
}
template <class T>
struct is_union_or_class1 : public detail::is_union_or_class_helper1<T> { };
然后我使用虚拟空类测试它,value
成员评估为false
。然后我使用void_t
重试它:
#include <type_traits>
template <class...>
using void_t = void;
namespace detail {
template <class T, class = void_t<T>>
struct is_union_or_class_helper2 : public std::false_type { };
template <class T>
struct is_union_or_class_helper2<T, void_t<char T::*>> : public std::true_type { };
}
template <class T>
struct is_union_or_class2 : public detail::is_union_or_class_helper2<T> { };
这一次它正确地评估了true
。为什么结果不同?在char T::*
是有效表达式的情况下,两个助手都更专业,为什么只有在第二种情况下助手继承自true_type
?这是测试代码:
struct dummy_type { };
int main(int argc, char** argv) {
std::cout << is_union_or_class1<dummy_type>::value << "\n";
std::cout << is_union_or_class2<dummy_type>::value << "\n";
}
我使用MSVC 2015编译器编译了此代码并进行了测试。
答案 0 :(得分:1)
考虑一下:
is_union_or_class1<dummy_type>::value
dummy_type
不是指向要推导出的类T
的char类型的数据成员的指针。换句话说,dummy_type
(我说)不匹配类型char T::*
,此专业化将被废弃。
因此,选择了类模板,并且该模板继承自std::false_type
:
template <class T>
struct is_union_or_class_helper1 : public std::false_type { };
这样的事情会起作用:
template <class T, typename = T>
struct is_union_or_class_helper1 : public std::false_type { };
template <class T>
struct is_union_or_class_helper1<T, decltype((char T::*){}, T{})> : public std::true_type { };
这只不过是void_t
成语的另一种变体
让我重写一下:
template <class T, typename = void>
struct is_union_or_class_helper1 : public std::false_type { };
template <class T>
struct is_union_or_class_helper1<T, decltype((char T::*){}, void())> : public std::true_type { };
它就是那些仍然在等待C ++ 17的void_t
成语的形式之一。