为 r 值引用系统地重载是一个好的模式吗?

Is overloading systematically for r-value references a good pattern?

我有一个 class,其行为与 std::ostream(的 C++11 版本)非常相似,我可以向其流式传输许多不同(不相关)的类型。

class mystream{...some implementation...};

要定义的典型函数是

mystream& operator<<(mystream& ms, type1 const& t1){...}

mystream& operator<<(mystream& ms, type2 const& t2){...}

等等

但是,(就像 C++11 的流一样)我想在构建时流式传输。例如:

mystream{} << t1;

为了能够做到这一点,我为每种类型重载了左值引用:

mystream& operator<<(mystream&& ms, type1 const& t1){
   return ms << t1; // this calls the l-value version
}

代码并不复杂,但它是重复的,因为我必须对涉及的所有类型都这样做。由于这个class的性质,它是有道理的在引用和左值引用上使用。

问题是这是否是正确的方法?我应该为每种类型编写两个函数吗?这个模式好吗?

第二个问题:当然我可以做一些模板魔术来在适当的时候接受左值引用,但我还是不知道这是否是推荐的路径。

三元题:函数return mystream&(同上)还是mystream&&.


这是示例代码:

class A{};
class B{};

class mystream{};

mystream& operator<<(mystream& ms, A const& a){return ms;} // (1)
mystream& operator<<(mystream& ms, B const& b){return ms;} // (2)

mystream& operator<<(mystream&& ms, A const& a){return ms; /*ms << a;*/} // (3)
mystream& operator<<(mystream&& ms, B const& b){return ms; /*ms << a;*/} // (4)

int main(){

    mystream ms;
    ms << A{};
    ms << B{};

    mystream{} << A{}; // ok only if line (3) is defined
    mystream{} << B{}; // ok only if line (4) is defined

}

如果我注释第 (3) 行,错误消息是

fatal error: invalid operands to binary expression ('mystream' and 'A')
        mystream{} << A{}; // ok only if line (3) is defined
        ~~~~~~~~~~ ^  ~~~
././random.hpp:146:11: note: candidate function not viable: expects an l-value for 1st argument
mystream& operator<<(mystream& ms, A const& a){return ms;} // (1)

如果我注释第 (1) 行,则相反的情况发生

fatal error: invalid operands to binary expression ('mystream' and 'A')
        ms << A{};
        ~~ ^  ~~~
././random.hpp:149:11: note: candidate function not viable: no known conversion from 'mystream' to 'mystream &&' for 1st argument
mystream& operator<<(mystream&& ms, A const& a){return ms; /*ms << a;*/} // (3)

C++ 定义了一个采用 ostream 右值引用的函数模板:

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

它调用适当的插入运算符。因此,你应该只定义

template <typename X>
mystream& operator<< (mystream&& ms, const X& x)
{
    ms << x;
    return ms;
}