【问题标题】:Traits to detect if a class is compatible with std::ostream<<检测类是否与 std::ostream<< 兼容的特征
【发布时间】:2017-06-19 22:11:43
【问题描述】:

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

我的实现试图从 SFINAE 中受益,以检测函数 std::ostream&amp; operator&lt;&lt;(std::ostream&amp;, const MyClass&amp;) 是否可用于该类。不幸的是,它在应该与 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。 如果您需要更多详细信息,请不要犹豫。

【问题讨论】:

    标签: c++ c++11 sfinae ostream g++4.9


    【解决方案1】:

    这是 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

    【讨论】:

      猜你喜欢
      • 2014-05-10
      • 2020-10-06
      • 2012-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-15
      • 2010-11-20
      相关资源
      最近更新 更多