4

関数ポインター テンプレート パラメーターとして、既定の引数を持つ関数を使用しようとしています。

template <void (*F)()>
class A {};

void foo1(int a = 0) {}
void foo2() {}

int main() 
{
    //A<foo1> a1;   <-- doesn't work
    A<foo2> a2;
}

コンパイラ エラーは次のとおりです。

main.cpp:7:7: エラー: テンプレート引数 'foo1' を 'void (*)()' に変換できませんでした</p>

これが機能するための特定の構文はありますか? それとも特定の言語制限ですか? それ以外の場合は、デフォルト パラメータの代わりに 2 つの個別の関数を使用することもできます。

void foo1(int a) {}
void foo1() { foo1(0); }

更新 署名が異なることは理解していますが、デフォルトのパラメーターですべての関数を変更する必要なく、これを便利に機能させる方法があるかどうか疑問に思っていますか?

4

5 に答える 5

3

の署名foo1void(int)、ではありませんvoid()。これが、 に変換できない理由void(*)()です。

デフォルト引数とオーバーロードを混同しています。

于 2012-11-16T23:00:17.130 に答える
2

C ++標準のセクション8.3.6によると、

パラメータ宣言で式が指定されている場合、この式がデフォルトの引数として使用されます。デフォルトの引数は、末尾の引数が欠落している呼び出しで使用されます。

A<foo1>は関数の呼び出しではないため、デフォルトの引数は無視されます。実際、これらは、関数の呼び出しを除くすべてのコンテキストで無視されます。たとえば、

typedef void (*FFF)();
FFF x = foo1;

foo1コンパイルされず、テンプレートパラメータとして使用しようとしたときに表示されるのと同じメッセージが生成されます。

error: invalid conversion from ‘void (*)(int)’ to ‘void (*)()’

デフォルトの引数の評価は呼び出しの別のステップであるため、これは理にかなっています。

8.3.6.9:デフォルトの引数は、関数が呼び出されるたびに評価されます。

デフォルトの引数が存在しても、関数のシグネチャは変更されません。たとえば、デフォルトの引数を持つ単一引数関数を使用して、引数なしの仮想メンバー関数をオーバーライドすることはできません。

于 2012-11-16T23:05:24.157 に答える
2

デフォルトの引数値は関数型の一部ではありません。foo1引数を 1 つ取るため、引数をとらない関数として使用することはできません。言及しなくても議論は埋められますが、まだそこにあります。

ディスパッチ機能を使用した回避策は、良い解決策のように思えます。たくさん必要な場合は、テンプレート化することもできます。

于 2012-11-16T23:00:09.843 に答える
2

関数ポインターには、すべてのデフォルトパラメーターが展開された関数の署名があり、関数ポインターは別の署名を持つ関数ポインターに変換できないと確信しています。ただし、これを標準で見つけることは別の問題です...

標準の関連条項は 8.3.5 [dcl.fct] パラグラフ 6 だと思います。

... 戻り値の型、parameter-type-list、ref-qualifier、および cv-qualifier-seq は関数の一部ですが、デフォルトの引数 (8.3.6) または例外仕様 (15.4) は含まれません。タイプ。[ 注: 関数型は、関数へのポインター、関数への参照、およびメンバー関数へのポインターの代入および初期化中にチェックされます。—終わりのメモ]

デフォルトの引数= valueは、 8.3.6 [dcl.fct.default] パラグラフ 1 に従った形式の人であることに注意してください。

parameter-declaration で initializer-clause が指定されている場合、この initializer-clause がデフォルトの引数として使用されます。...

于 2012-11-16T23:01:12.697 に答える
1

foo1署名があるため、コンパイルされません。

void foo1(int a);

あなたがへのポインタに固執しようとしているもの:

void F()

関数のシグネチャが一致しません。デフォルトのパラメーターがあるという事実foo1は、関数のシグニチャーを変更しません(それでもを取り込むことができますint)。

より一般的なソリューション

テンプレートは忘れてください。ここでは制限されているだけです。

個人的には、コールバックの問題を解決する方法は、引数バインディングを持つ関数オブジェクトを使用することです。これは、boost :: functionライブラリを使用し、デフォルトの引数をboost :: bind(またはand )でバインドすることで実行できます。std::bind1ststd::bind2nd

std::functionこれらのブーストライブラリは、、、およびのように、新しいC++11標準にも組み込まれていstd::bindます。

関数にデフォルトの引数を提供したり、クラスメンバー関数をコールバックとして使用したりするなど、非常に優れた処理を実行できるため、これを確認する価値は十分にあります。

私がリンクしたすべてのサイトにはたくさんのサンプルコードがあり、ブーストリンクにはチュートリアルがあります。

于 2012-11-16T23:04:45.720 に答える