c++ - 检查 C++11 中运算符是否存在的最佳方法

标签 c++ c++11 operators typetraits

<分区>

我需要检查给定的类是否有 <<(cls, ostream)运营商定义与否。如果是这样,我希望我的函数使用它来写入 ostringstream ,否则应使用样板代码。

我知道以前有人问过这个问题。但是,我通常会发现自定义解决方案并不总是适用于我的编译器 (clang++)。经过几个小时的搜索,我终于找到了 boost::type_traits。我之前没有看过那里,因为我假设 c++11 已经复制了 boost 具有的特性部门中的所有内容。

对我有用的解决方案是:

template <typename C>
std::string toString(C &instance) {
    std::ostringstream out;
    out << to_string<C, boost::has_left_shift<C, std::ostream>::value>::convert(ctx);
    return out.str();
}

to_string定义为:

template <typename C, bool>
struct to_string {
    // will never get called
    static std::string convert(LuaContext &ctx) {}
};

template <typename C>
struct to_string<C, true> {
    static std::string convert(LuaContext &ctx) {
        return "convert(true) called.";
    }
};

template <typename C>
struct to_string<C, false> {
    static std::string convert(LuaContext &ctx) {
        return "convert(false) called.";
    }
};

所以我发布这个有两个原因:

  1. 检查这是否是最明智的使用方法,或者看看其他人是否可以提出更好的解决方案(即这个问题更多是出于对方法的好奇,而不是“这行得通吗?”——它已经行得通了对我来说)

  2. 发布此信息可以节省其他人的搜索时间,以防她/他也需要做类似的事情。

  3. 作为一个更普遍的问题——有时特征类似乎返回 std::true_type 或 std::false_type(好吧,至少对于非增强类)。其他时候他们是 bool 值。这种差异是有原因的吗?如果boost:has_left_shift返回类型而不是 bool , 那么我可以只有一个 to_string结构。

最佳答案

快速而简单的 C++11 SFINAE:

template<typename T,
         typename = decltype(
           std::declval<std::ostream&>() << std::declval<T const&>()
         )
>
std::string toString(T const& t)
{
    std::ostringstream out;
    // Beware of no error checking here
    out << t;
    return out.str();
}

template<typename T,
         typename... Ignored
>
std::string toString(T const& t, Ignored const&..., ...)
{
    static_assert( sizeof...(Ignored) == 0
                 , "Incorrect usage: only one parameter allowed" );
    /* handle any which way here */
}

如果需要,还可以检查 stream << val 的返回类型确实可以转换为 std::ostream& :

template<typename T,
         typename Result = decltype(
           std::declval<std::ostream&>() << std::declval<T const&>()
         ),
         typename std::enable_if<
             std::is_convertible<Result, std::ostream&>::value,
             int
         >::type = 0
>

至于一个不太快捷的解决方案,我会介绍一个 is_stream_insertable trait,哪个实现可以使用此处使用的相同技巧。

请注意 std::integral_constant<bool, B>有一个到 bool 的转换运算符,这可能会解释您观察到的一些事情。我也不建议将 C++11 标准类型和特征与 Boost 混合使用:不要混淆 std::true_typeboost::true_type !这并不是说你不应该使用例如Boost.TypeTraits 完全适用于 C++11,但尽量保持一致并且一次只使用两者之一。

关于c++ - 检查 C++11 中运算符是否存在的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12980508/

相关文章:

java - 如何使用 JNI 将 Java 中的 ArrayList<Integer> 转换为 C++ int 数组?

c++如何实现类成员之间的切换

c++ - 关于命名空间和模板参数的名称问题

javascript - 是什么原因?运算符或使用字符串?

operators - Cakephp 1.3 使用 OR XPATH 运算符设置::extract

shell - 使用 ! shell 命令上的运算符

c++ - Directx 11 Bitblt 替代方案

c++ - View 和跨步 View 的函数模板特化和 const 噩梦

c++ - 自动识别合适的类型,足够大且足够精确,以保存容器中所有元素的总和

c++ - 如何禁用隐式构造函数转换,同时允许复制初始化