如何使用enable_if有条件地定义<<运算符

How to use enable_if to conditionally define a << operator

本文关键字:lt 定义 运算符 有条件 何使用 enable if      更新时间:2023-10-16

我想定义一个<<类集合的操作符;集合是开放的,但是所有的成员都有一个共同的标记基类,并且都有一个成员函数std::string String() const。基本上,我得到的是:

class Tag {};
class Obj : public Tag
{
public:
    std::string String() const { return "specialized"; }
};
template <typename T>
typename std::enable_if<std::is_base_of<Tag, T>::type, std::ostream>::value& operator<<( std::ostream& dest, T const& source)
{
    dest << source.String();
    return dest;
}
int
main()
{
    std::cout << typeid(std::enable_if<std::is_base_of<Tag, Obj>::value, std::ostream>::type).name() << std::endl;
    std::string s( "generic" );
    Obj e;
    std::cout << e << std::endl;
    std::cout << s << std::endl;
    return 0;
}

这不起作用:对于g++(版本4.8.3,用-std=c++11调用),我得到错误消息:

enableIf.cc: In function 'int main()':
enableIf.cc:55:18: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
     std::cout << e << std::endl;
                  ^
In file included from /usr/lib/gcc/x86_64-pc-cygwin/4.8.3/include/c++/iostream:39:0,
                from enableIf.cc:8:
/usr/lib/gcc/x86_64-pc-cygwin/4.8.3/include/c++/ostream:602:5: error:   initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = Obj]'
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
     ^

我不能弄清楚,因为没有任何右值引用;编译器似乎碰到了标准库中std::ostream&&的泛型过载。

在MSC (VS 2013)中,错误消息要详细得多,但它以:

开头。
enableIf.cc(55) : error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'Obj' (or there is no acceptable conversion)

,然后继续列出了许多可能的函数,它们都在标准库中。

(在我的实际代码中,第55行对应于std::cout << e << std::endl;行。)

在这两种情况下,编译器似乎都拒绝了我的重载函数。但是,如果我注释掉<<行,代码就会编译,并且main中第一行的输出值似乎是正确的(至少使用MSC— g++的输出是So,不管这意味着什么)。

假设两个编译器一致,我假设我的代码中有错误,但我不知道是什么。你是怎么做到的?(FWIW:我同样很高兴,甚至更高兴,与一个解决方案,产生重载的所有类型有一个成员函数std::string Type::String() const)

我很确定你是这个意思:

template <typename T>                        //  here                 here
typename std::enable_if<std::is_base_of<Tag, T>::type, std::ostream>::value& 
operator<<( std::ostream& dest, T const& source)

等于:

template <typename T>
typename std::enable_if<std::is_base_of<Tag, T>::value, std::ostream>::type& 
operator<<( std::ostream& dest, T const& source)