2011-02-21 8 views
13

N3225のサブセクション20.8.10.1std::bindの説明を読み終えませんでした。それは、次のように1を印刷しなければならないと言いますが、bindはその引数をコピーすることになっているので、0を印刷する必要があります。渡された引数を参照する場合は、std::refを使用する必要があります。何がstd :: bind(x、y)は何をしますか?

void f(int &a) { a = 1; } 

int main() { 
    int a = 0; 
    std::bind(f, a)(); 
    std::cout << a << std::endl; 
} 

GCC出力0、私は物事が仕事と思ったものと同意。しかし、N3225はstd::bind(f, a1)INVOKE(f, v1)を呼び出しますwrapper()によって呼び出されたときv1(私は、std::forward<A1>(a1)完璧な転送パラメータであるbindsの入ってくるパラメータを使用して、他の言葉で、渡された引数)aしなければならないことを呼び出しラッパーを返還しなければならないと述べています。

INVOKE(f, a)は、20.8.2~f(a)で定義されます。したがって、これは、返された呼び出しラッパーの呼び出しが元の引数を渡すことを定義します。私は何が欠けていますか?

+0

http://stackoverflow.com/questions/4327474/does-perfect-forwarding-in-c0x-make-reference-wrapper-deprecated(重複はしませんが関連性はありますか?C + + 0x) – CashCow

答えて

2

うわー、これは信念を超えて混乱しています。それはv1tidと定義し、次のとおりです(tiはi番目の完全転送バインドパラメータです)。TiDはそのパラメータの減衰型です。つまり、配列はポインタなどになります。

tidstd::forward<Ti>(ti)

よしから構築されたタイプTiDの左辺値ですが、私はこのtidstd::forward<Ti>(ti)であり、それは左辺値だ、と言いました!しかし、これは本当に言うことではありません。それは

tidそれは今はるかに理にかなってstd::forward<Ti>(ti)

から構築されたオブジェクトを参照するタイプTiDの左辺値であることを意味します。なぜなら、std::forward<Ti>(ti)が実際には右辺値なのですから? "左辺値は...から構築されました"は、 "..."から新しいオブジェクトを作成し、左辺値がそれを参照することを意味します。

3

std :: bindを呼び出した時点で、参照を渡すことを知らないため、現在は0を出力します。関数のシグネチャを調べて、それに応じてどのようなパラメータ型が使用され、調整されるかはわかりません。それを動作させるために

適切に呼び出す

void f(int &a) { a = 1; } 

int main() { 
    int a = 0; 
    std::bind(f, std::ref(a))(); 
    std::cout << a << std::endl; 
} 

C++ 0xのは、「無線綴じ」を提案しているが、ひどく現在の行動に依存している静かに既存のコードを壊す可能性があり、この巨大な危険性があります。ここには非常に簡単な例があります。あなたはstrで渡すので、それが有効になるという事実は、コールバックの呼び出しを来た文字列をコピーし、バインドに頼ることができます現時点では

void myCallback(const std::string& str, int i); 

function< void(int) > makeCallback(const std::string & str) 
{ 
    return bind(myCallback, str, _1); 
} 

リファレンスとして保存するために「スマートに」「完璧なバインディング」を使用した場合、このような状況が発生します。

+2

元のポスターは明らかに 'std :: ref'を使うことを知っています。彼は仕様書をどのように解釈すべきかを質問しました*コードプリント1を作る方法ではない*ので、これは答えではありません。 –

+0

明示的なstd :: refを強制的に使用することは非常に危険なのです。確かにそれは直接質問に答えると私は本当にこれらのすべてのtidものを理解していない... – CashCow

5

それは次のようなし1

を印刷する必要がありますと言う、それはそれを言っていません。

渡された引数を参照する場合は、std :: refを使用する必要があります。

はい。

しかし、N3225はSTD ::バインド(F、A1)ラッパー(によって呼び出されたときに、そのコールのラッパーを返還しなければならないが)v1は、私が合格(引数でなければならINVOKE(F、V1)を、呼ぶことを言いますつまり、完全な転送パラメータであるbind :: incoming(a1))を使用します。

あなたが間違っている場所です。バインド呼び出しで渡された「バインドされた引数」は、タイプTiDの新しく作成されたオブジェクトの形式で格納され、それぞれがからに構成されています。これは、「tidは、タイプの値の左辺であり、からstd::forward<Ti>(ti)に設定されています。参照ラッパーの特別な処理のために、追加の「変換レイヤー」があります。 viおよびVitidおよびTiDにどのように関連しているかを説明する20.8.10.1.2/10を参照してください。

+0

私には、 'の値は、' '(ti)'から '' TiD''が ''前方(ti) 'は左辺値になり、'(TiD&)forward (ti) 'のように 'TiD'にキャストされ、左辺値になるものとする。左辺値が指し示す新しいオブジェクトを作成すると言って読める方法はありません。そのような場合、左辺はその新しいオブジェクトに名前を付けることによって構築されるでしょう。 IMOは非常に混乱する方法です。 –

+0

"構成"は "オブジェクト"を意味します。 '(TiD&)forward (ti)'にはオブジェクトの構築が行われていません。左辺値の参照はオブジェクト型ではありません。 – sellibitze

+0

"構築"は、オブジェクトを作成する以外のことを意味する可能性があります。 「構文規則[...]に従って構築されたC++プログラム」(「整形式」の定義)と比較してください。 「構築する」は、「左辺を構築する」と一緒に使用されても、オブジェクトを作成することを意味するものではありません。左辺値を構築することは、それが何を言うのかを意味するだけで、他のものは意味しません。次のコードは、識別子 'x'から左辺値を構成します: 'int main(){int x = 0;バツ; } '。次のコードでは、左辺値は生成されません。* 'int main(){int x = 0; } '。 –

関連する問題