2016-09-02 4 views
5

私はstd::forwardを学んでいます。なぜC++の文字列で目的の関数を呼び出すためにstd :: forwardが必要ないのですか?

#include <iostream> 
#include <typeinfo> 
#include <string> 
using namespace std; 

class Example { 
}; 

ostream &operator << (ostream &os, const Example &e) { os << "yes!"; return os; } 

void test_forward_inner(const Example &e) { cout << "& " << e << endl; } 
void test_forward_inner(Example &&e) { cout << "&& " << e << endl; } 

void test_forward_inner(const string &e) { cout << "& " << e << endl; } 
void test_forward_inner(string &&e) { cout << "&& " << e << endl; } 

template <typename T> 
void test_forward_wrapper(T &&arg) { 
    test_forward_inner(arg); 
} 

int main() 
{ 
    Example e; 
    test_forward_wrapper(e); 
    test_forward_wrapper(Example()); 

    cout << endl; 

    string s("hello"); 
    test_forward_wrapper(s); 
    test_forward_wrapper("hello"); 

    return 0; 
} 

ここで私はtest_forward_wrapper()からtest_forward_inner()に左辺値と右辺値を転送しようとした:私たちは、別の関数呼び出しの引数を転送する前にstd::forwardを呼び出さない場合に何が起こるかテストするための短いプログラムを書きました。このプログラムを実行すると、出力できます:

& example 
& example 

& hello 
&& hello 

std::stringに対するS、目的の内部関数が呼び出されましたが、私自身のクラスのためにのみ左辺値のバージョンが呼び出されました。引数が内部関数に渡される前にstd::forwardを呼び出すだけで、rvalueバージョンが呼び出されます。

ここで違いは何ですか?私が知っているように、参照の折りたたみ規則に従って、ラッパーがExample()で呼び出されたとき、TExampleと推定され、argExample &&となるため、内部関数の右辺のバージョンを呼び出す必要があります。

ここでstd::stringのような状況では、内部関数の正しいバージョンが呼び出されました。ここでstd::forwardを削除できますか?そうでない場合は、何が起こるのでしょうか?

答えて

7

"hello"std::stringではありません。const char[6]です。 test_forward_wrapper()は関数テンプレートです。テンプレート引数Tは、char const (&)[6]と推定されます。

test_forward_wrapper()の内部には、const char[6]と呼ばれ、最初はstd::stringに変換する必要があります。これは一時的なstd::stringです。つまり、値はrvalue参照にバインドされていることが好ましいため、test_forward_inner(string &&)が呼び出されます。

正確なstd::stringtest_forward_wrapper()に渡すと同じ結果になります。

test_forward_wrapper(std::string("hello")); 
4

違いは

test_forward_wrapper("hello"); 

に "ハロー" ここstd::stringではないということです。それはconst char *です。

test_forward_wrapper(std::string("hello")); 

そして結果は、カスタムクラスのと同じになりますに変更し、これを。

+1

重要な部分は、内側機能のみSTRING' 'への変換が発生手段'のstd :: STRING'を受け入れ、ないがラッパーは、(そう全く強制そのコールで発生していない)テンプレートであることです(内部関数へのr値参照を提供する)、転送は伴わない。 – ShadowRanger

+3

'' hello "'は 'const char *'ではなく、 'const char [6]'で 'const char *'に崩壊することができます。 。 –

+1

^(この状況では減衰しません) –

関連する問題