【问题标题】:best way to check for existence of an operator in c++11 [duplicate]在c ++ 11中检查运算符是否存在的最佳方法[重复]
【发布时间】:2012-10-19 18:43:46
【问题描述】:

我需要检查给定类是否定义了<<(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 (嗯,至少对于非增强类)。其他时候它们是布尔值。这种差异有原因吗?如果boost:has_left_shift 返回一个类型而不是bool,那么我可以只有一个to_string 结构。

【问题讨论】:

    标签: c++ c++11 operators typetraits


    【解决方案1】:

    简明扼要的 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 &lt;&lt; val 的返回类型是否确实可以转换为std::ostream&amp;

    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&lt;bool, B&gt; 有一个到bool 的转换运算符,这可能解释了您观察到的一些事情。我也不建议将 C++11 标准类型和特征与 Boost 混合:不要将 std::true_typeboost::true_type 混淆!这并不是说你不应该使用例如Boost.TypeTraits 完全适用于 C++11,但尽量保持一致,一次只使用两个中的一个。

    【讨论】:

    • 抱歉这么久才批准,直到现在我才有机会试用代码!
    • 这不会为我编译(VS2012):错误 C4519:默认模板参数只允许在类模板上使用(以及一些后续错误)这是由于缺少 c++11 合规性在 msvc 中?
    • @ViktorSehr 很有可能。
    猜你喜欢
    • 2017-01-16
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多