元程序确定一个类是否输出流意外输出

时间:2014-01-22 22:28:41

标签: c++ templates c++11 metaprogramming template-meta-programming

我以为我已经想出了如何创建一个模板来确定一个类/结构是否可以流入一个ostream(例如,“可打印”)但是我写的模板中存在一个缺陷。希望了解我出错的地方以及使模板按照我期望/想要的方式工作的任何解决方案。

所以我的问题是

  1. 我错过了一些非常基本的东西,还是比模板考虑的更复杂?
  2. 我没有看过模板与右值参考的交互:它们也会对模板造成问题吗?
  3. 完整代码here


    这是模板

    template<typename T, typename U>
    class isOutputStreamable {
      private:
        template<typename V, typename W> static decltype(operator<<(std::declval<V>(), std::declval<W>()), std::true_type()) check_(int);
        template<typename, typename> static std::false_type check_(...);
      public:
        static const bool value = decltype(check_<T, U>(0))::value;
    };
    

    我正在测试的课程

    struct Empty {
    };
    
    struct Streamer {
    };
    
    std::ostream& operator<<(std::ostream& ostream, const Streamer&) {
      return ostream << "Streamer";
    }
    

    static_asserts以我期望的方式工作

    // Streamer should show as ostreamable
    static_assert( isOutputStreamable< std::ostream&, const Streamer& >::value, "Goodness" );
    static_assert( isOutputStreamable< std::ostream&, const Streamer  >::value, "Goodness" );
    static_assert( isOutputStreamable< std::ostream&,       Streamer& >::value, "Goodness" );
    static_assert( isOutputStreamable< std::ostream&,       Streamer  >::value, "Goodness" );
    
    // isOutputStreamable works with a value ostream for Streamer
    static_assert( isOutputStreamable< std::ostream, const Streamer& >::value, "Goodness" );
    static_assert( isOutputStreamable< std::ostream, const Streamer  >::value, "Goodness" );
    static_assert( isOutputStreamable< std::ostream,       Streamer& >::value, "Goodness" );
    static_assert( isOutputStreamable< std::ostream,       Streamer  >::value, "Goodness" );
    
    // Empty should not show as ostreamable
    static_assert( !isOutputStreamable< std::ostream&, const Empty& >::value, "Goodness" );
    static_assert( !isOutputStreamable< std::ostream&, const Empty  >::value, "Goodness" );
    static_assert( !isOutputStreamable< std::ostream&,       Empty& >::value, "Goodness" );
    static_assert( !isOutputStreamable< std::ostream&,       Empty  >::value, "Goodness" );
    
    // With a const ostream nothing should show as ostreamable
    static_assert( !isOutputStreamable< const std::ostream&, const Streamer& >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream&, const Streamer  >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream&,       Streamer& >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream&,       Streamer  >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream , const Streamer& >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream , const Streamer  >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream ,       Streamer& >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream ,       Streamer  >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream&, const Empty&    >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream&, const Empty     >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream&,       Empty&    >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream&,       Empty     >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream , const Empty&    >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream , const Empty     >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream ,       Empty&    >::value, "Goodness" );
    static_assert( !isOutputStreamable< const std::ostream ,       Empty     >::value, "Goodness" );
    

    然后是

    的static_asserts
    // Unexpected results: I wanted these to all fail
    static_assert( isOutputStreamable< std::ostream, const Empty& >::value, "Badness" );
    static_assert( isOutputStreamable< std::ostream, const Empty  >::value, "Badness" );
    static_assert( isOutputStreamable< std::ostream,       Empty& >::value, "Badness" );
    static_assert( isOutputStreamable< std::ostream,       Empty  >::value, "Badness" );
    

    提前感谢您的帮助。


    更新

    @Casey:谢谢你的帮助。我确信模板有问题我想我完全错过了它可能实际上正确匹配的事实。至于你关于如何切换模板的建议肯定是很容易做到的事情;但是,我很好奇,如果没有其他解决方案适合我接下来会说的话。

    模板实际上是根据我希望创建这些类型的检查器模板的通用宏生成的

       #define BINARY_FUNCTION_EXISTS_(FUNCTION_NAME_, CHECK_NAME_) \
        template<typename T, typename U> class CHECK_NAME_ {\
          private:\
            template<typename V, typename W> static decltype(FUNCTION_NAME_(std::declval<V>(), std::declval<W>()), std::true_type()) check_(int);\
            template<typename, typename> static std::false_type check_(...);\
          public:\
            static const bool value = decltype(check_<T, U>(0))::value;\
        };
    

    是否因为(在我的情况下不合适)匹配模板,这个可以使用ostream的模板需要特殊情况?我认为答案是肯定的,但我已经对此一直感到困惑,并且要求它并没有什么坏处。再次感谢。

1 个答案:

答案 0 :(得分:4)

1。标准库定义了一个无约束的模板函数,它根据左值流插入为所有类型提供右值流插入:

  

C ++11§27.7.3.9右值流插入[ostream.rvalue]

template <class charT, class traits, class T>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&& os, const T& x);
     

1 效果: os << x

     

2 返回: os

这显然会破坏你对rvalue ostreams的检测。

2。由于decltype(std::declval<T>())decltype(std::declval<T&&>())都是T&&,因此对于右值引用,它可以正常工作; IsOutputStreamable<T, U&&>::value将等于IsOutputStreamable<T, U>::value