2

我试图实现一个 type_traits 能够检测一个类是否可以在指令的上下文中使用,例如:std::cout << my_class_instance;.

我的实现试图从 SFINAE 中受益,以检测该函数std::ostream& operator<<(std::ostream&, const MyClass&)是否可用于该类。不幸的是,它在应该与 C++ 11 兼容的 g++-4.9 下失败。其他编译器没有抱怨,似乎生成了正确的代码: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 。如果您需要更多详细信息,请不要犹豫。

4

1 回答 1

2

这是 gcc 如何解释的问题:

template <class... Ts> using void_t = void;

在它处理特别影响该问题的核心语言问题之前(1558)。基本上,gcc 看到这个别名不受模板参数的影响,只是放入void. 这完全违背了void_t如果它总是成功的目的,这就是在这种情况下发生的事情。

您可以通过包装void_t另一个模板来欺骗它(如原始论文中所建议的那样):

template <class... Ts> struct make_void { using type = void; };            
template <class... Ts> using void_t = typename make_void<Ts...>::type;

在这里, gcc 不能仅仅放弃替代,因为当然假设还有一些其他make_void专业化不仅仅是void.

于 2017-02-02T17:54:35.080 回答