2012-11-06 2 views
18

バインドから返されたオブジェクトは余分な引数を無視するのはなぜですか?

void f(int x, int y); 

、私は2つの引数を取る関数があると仮定し、私はそれらのいずれかをバインドします。次のように私はstd::bindを使用することができます。

auto partiallyBoundF = std::bind(f, 10, _1); 

partiallyBoundFは、引数を1つしかかかりますが、私は、複数でそれを呼び出すことができます。

partiallyBoundF(20, 0); 
partiallyBoundF(0, 44, -99, "Hello", 4.5, true, []{}); 

追加の引数を渡すことが許可オブジェクトの目的はbindから返されるもの:最初越えた引数は、さらに任意の理にかなっているタイプである必要はありませんか?これは、他の場所で拒否される呼び出しエラーをコンパイルすることを可能にします。

+3

どのようなコンパイラですか?これらの追加引数を許可することは実際には意味をなさないので、標準に準拠していないコンパイラである可能性があります。例えば、MSVCはバリデーショナルテンプレートを最大限に活用するようにバリデーショナルテンプレートを定義するだけで、バリデーショナルテンプレートをエミュレートし、NILタイプにデフォルト設定します。それはあなたの行動の原因でしょうか? –

+3

@ChristianRau:これは標準の一部です。それもTR1の一部でした。 20.8.2/4は、バリデーションテンプレート化された 'operator()'が、引数の型や数にかかわらず、渡されたものをそのまま受け入れることを想定しているとのコメントをしています。 TR1も同様の表現をしています。 – KnowItAllWannabe

+1

あなたのケースでは、 'N = sizeof ...(bound_args)'(呼び出しをバインドする引数の数)は有効な式でなければなりません。20.8.9.1.2/2を参照してください。 20.8.2/1。編集:それはそれを呼び出すための他の方法を禁止しません。 – dyp

答えて

16

余分な引数を無視すると、実装するのがずっと簡単になり、実際には役に立ちます。

たとえば、 libstdC++(g ++)のアプローチは、タプルにoperator()引数を集めて、std::placeholderバインド引数に必要に応じて引数を抽出させる方法です。引数の数を強制するには、使用するプレースホルダの数を数える必要がありますが、これはかなり複雑です。バインド呼び出し可能関数は、複数のまたはテンプレート化されたoperator()呼び出しパターンを持つファンクタである可能性があります。したがって、バインドオブジェクトoperator()は単一の「正しい」署名で生成できません。

はまた、あなたが書くことができることに注意してください。

std::bind(&foo, std::placeholders::_1, std::placeholders::_3); 

すなわち、明示的にバインドオブジェクトへの第二引数を無視します。 bindが引数カウントを実施した場合は、それを指定する別の方法が必要です。 4番目の議論も無視されました。有用性については

、信号にメンバーシグナルハンドラをバインド考える:

sig.connect(std::bind(&C::on_sig, this, param, std::placeholders::_1)); 

sigは、余分な不要輻射のパラメータを持っている場合、それらは単にbindオブジェクトによって無視されます。それ以外の場合、同じハンドラを複数のシグナルにバインドするには、実際の目的ではない複数の転送ラッパーを記述する必要があります。

+3

"もっと役に立つ" - 私はそれについて議論するだろう。これは厳しいタイピングを破ります。そして、必要に応じて、この動作は、可変引数を受け入れるプロキシファンクタを使用するだけで、厳密な 'std :: bind'でエミュレートすることができます。 –

+2

@KonradRudolph呼び出し可能オブジェクトが複数の 'operator()'を持つファンクタである場合、バインド式は一般的な型では明確な型を持っていません。 – ecatmur

+0

ラムダを使用して4番目の引数を無視できます。しかし、それほど素晴らしいことではありません。 – dyp

関連する問題