2013-02-14 24 views
5

私がC++ 11のリファレンスを理解する限り、左辺は一時的にバインドされていて、左辺は絶対値にバインドされてはならないため、左辺の参照は(非const)左辺参照にバインドできません。一時的。私はライン(X)s << Dummy()を記述する場合、C++はなぜ私はstd :: stream rvalue refをlvalue refに移動できますか?

言って、ライン (A)に文句(私は限り私ができるように減少)連動の一時ストリームオブジェクト

struct Dummy {}; 
template <typename Stream> 
Stream& operator<<(Stream& s, Dummy) { 
    return s << ".";   // <- (A) 
} 

template <typename Stream> 
void pass(Stream&& s) { 
    std::move(s) << Dummy(); // <- (X) rvalue->lvalue conversion? 
} 

#include <fstream> 
int main() { 
    pass(std::fstream("test",std::ios::out)); 
} 

にこの奇妙な振る舞いを見つけしかし

error: invalid initialization of reference of type ‘std::basic_fstream<char>&’ from expression of type ‘std::basic_ostream<char>’

しかし、なぜコードは上記のようにをコンパイルし、期待通りに動作しますstd::moveによって返されたrvalue参照は、式sのように左辺値の参照にバインドできないようにする必要がありますが、gcc 4.6.1gcc 4.7.2の両方が同じように反応します。

なぜこの現象はストリームでしか機能しないように見えますか? T&を期待する関数にDummy&&を直接渡すと、std::moveの有無にかかわらず失敗します。

答えて

10

basic_ostreamは、次のようになりますoperator<<の過負荷を持っています

template <typename Elem, typename Traits, typename T> 
basic_ostream<Elem, Traits>& 
    operator<<(basic_ostream<Elem, Traits>&& sink, const T& val) 
{ 
    return sink << val; 
} 

これは§27.7.3.9[ostream.rvalue]で、標準で「右辺値ストリーム挿入」と呼ばれています。

右辺値から右辺値への暗黙的な変換(ソート)が可能です。basic_ostreamそれは特にtemporary streams to be usable without resorting to tricksを可能にするために導入されました。あなたが移動を省略する場合、コンパイルが失敗した理由については


Stream& operator<<(Stream& s, Dummy)なく移動呼び出されると、Streamstd::ostream(すなわちbasic_ostream<char>)から継承std::fstreamになります。

それはostreamされることを表現の結果を返すようにしようとした後、あなたの文字列を挿入するbasic_ostream<E, T>& operator<<(basic_ostream<E, T>&, const char*)オーバーロードを使用します。暗黙的にstd::ostream&からstd::fstream&へのダウンキャストはできないため、エラーが発生します。

あなたがそれ自身の行にsを返すことによってこの問題を解決することができます(それは暗黙のうちにupcastedされていません。)

あなたはその右辺値対を通過するので、これは動きに問題ではありません私たちが最初に発見した左辺値挿入演算子。この関数の内部では、ストリームはbasic_ostreamであるため、Streamも戻り値の型が一致します。

+1

です。それは意味をなさない。しかし、なぜ 'std :: move'が必要なのですか? – bitmask

+0

@bitmask:それがないと 's'は左辺値であるので、右辺値参照にバインドできません。 –

+0

@KerrekSB:しかし、(この答えに示されているように)右値参照ストリームがバインドするための完全なオーバーロードがあります。 'std :: move'の励まされることなく、そのオーバーロードがマッチしないのはなぜですか? – bitmask

関連する問題