我尝试实现一个能够检测类是否可以在指令上下文中使用的type_traits,例如:std::cout << my_class_instance;
。
我的实现试图从SFINAE中受益,以检测函数std::ostream& operator<<(std::ostream&, const MyClass&)
是否可用于该类。不幸的是,它在g ++ - 4.9下失败,它应该与C ++ 11兼容。其他编译器不抱怨并且似乎生成正确的代码:g ++ - 5 +,clang ++ - 3.3+以及Visual Studio。
这是我到目前为止尝试的实现:
#include <iostream>
#include <type_traits>
#include <vector>
template <class... Ts> using void_t = void;
template <class T, class = void> struct can_be_printed : std::false_type {};
template <class T> struct can_be_printed<T, void_t<decltype(std::cout << std::declval<T>())>> : std::true_type {};
static_assert(!can_be_printed<std::vector<int>>::value, "vector<int> cannot be printed");
static_assert(can_be_printed<int>::value, "int can be printed");
现场示例位于:https://godbolt.org/g/6xFSef。 如果您需要更多详细信息,请不要犹豫。
答案 0 :(得分:2)
这是gcc解释的问题:
template <class... Ts> using void_t = void;
在处理特别影响该核心语言(1558)的核心语言问题之前。基本上,gcc发现此别名不受模板参数的影响,只是在void
中下降。这完全违背了void_t
的目的,如果它总是成功的话,这就是在这种情况下发生的事情。
您只需将void_t
包装在另一个模板中(如original paper中所述)即可欺骗它:
template <class... Ts> struct make_void { using type = void; };
template <class... Ts> using void_t = typename make_void<Ts...>::type;
在这里,gcc不能放弃替代,因为当然假设其他make_void
专业化不仅仅是void
。