我尝试实现 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> { };
然后我使用虚拟空类和评估为 false
的 value
成员对其进行了测试。然后我使用 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 编译器进行了测试。
最佳答案
考虑一下:
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
惯用法的一种形式。
关于C++ 两个 is_union_or_class 实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44999372/