如何使用enable_if有条件地定义<<操作者

时间:2014-07-17 10:59:32

标签: c++ c++11

我正在尝试定义一个<<一组类的运算符;该集是开放的,但所有成员都有一个共同的标记基类,并且都具有成员函数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的所有类型生成重载的解决方案,我会同样高兴,甚至更开心。)

1 个答案:

答案 0 :(得分:3)

我很确定你的意思是:

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)

更改后,您可以成功编译。