How can I detect if a type can be streamed to an std::ostream?

前端 未结 6 1580
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-13 00:41

I\'m trying to write a type trait to detect if a type has overloaded operator<<() suitable to use to an output stream.

I\'m missing something because I\'m alwa

6条回答
  •  感动是毒
    2020-12-13 01:13

    It's apparently this overload of operator<< that's stepping in your way and making the expression in traling return type valid:

    template< class CharT, class Traits, class T >
    basic_ostream< CharT, Traits >& operator<<( basic_ostream&& os,
                                                const T& value );
    

    See (3) on this reference page. It's a simple forwarder (calling os << value) that was added in C++11 to allow insertion to rvalue-streams because they don't bind to overloads taking an lvalue reference.

    So, the problem is that std::declval() returns an rvalue reference and this overload kicks in. The call itself is well-formed, but because the function itself does not get instantiated you don't get an error even if value is not streamable.

    This can be sidestepped if you explicitly ask for lvalue reference: std::declval().

    I'd also suggest a slightly different implementation, without passing stream and value to test. You can use declval directly inside decltype. Together with comma operator, it looks like this:

    #include 
    #include 
    #include 
    #include 
    
    template
    class is_streamable
    {
        template
        static auto test(int)
        -> decltype( std::declval() << std::declval(), std::true_type() );
    
        template
        static auto test(...) -> std::false_type;
    
    public:
        static const bool value = decltype(test(0))::value;
    };
    
    class C {};
    
    int main() {
        std::cout << is_streamable::value << std::endl;
        return 0;
    }
    

提交回复
热议问题