为 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;
}
我有一个 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;
}