2011-08-18 34 views
8

申し訳ありませんがこれまでに質問されているが、私はそれを見つけることができませんでした。関数ポインタの代わりに値(?)で関数を渡す?

私はテンプレートと新しいC++ 11の機能(主にラムダ、私はいつも他の言語で好きなもの)について教えています。

しかし、私のテストで私はそれが働いていたわからなかった、と私はそれがどのように動作するかを理解しようとしているが、それを把握するカント何かに来ました。..

次のコード:

template <class Func> 
void Test(Func callback) { 
    callback(3); 
} 

void Callback(int i) { 
    std::cout << i << std::endl; 
} 

int main(int argc, char** argv) { 
    Test(&Callback); // this I was expecting to work, compiler will see its a pointer to a function 
    Test(Callback); // this also works, but how?! 
    return 0; 
} 

テンプレートの仕組みを理解していれば、基本的にはコンパイラが何をビルドするのかを知るスキームなので、最初のコールTest(&Callback);コンパイラはテンプレートが関数アドレスを受け取り、ポインタである。

しかし、2回目の呼び出しは何ですか?それを前提としたテンプレートは何ですか? functioのコピー(もしそれが意味をなささえすれば)?

答えて

14

関数は、それ自身のポインタに暗黙的に変換可能です。この変換はどこでも起こります。 Test(Callback)は、Test(&Callback)とまったく同じです。違いはありません。両方の場合において、Funcvoid(*)(int)であると推定される。

関数ポインタが奇妙です。それらについてもっと知ることができます"Why do all these crazy function pointer definitions all work?"

+0

答えに感謝します。ですから、テンプレートを使用してTestを宣言しなかった場合、void Test(void(* callback)(int)){...}でも両方の呼び出しがうまくいくでしょう。知っていることは良いことだ。あなたがリンクしているスレッドを読んでいることを確認してください。 – sap

3

C++では、関数はファーストクラスのオブジェクトではなく、 "値としての機能"が意味を持ちません。そのため、関数名は常に暗黙的にポインタに変換されています。

+0

「価値による機能」が意味をなす言語よりも注目に値するかもしれません。 – hamstergene

2

関数は暗黙的に関数ポインタに変換されます。実際には、関数の値や参照を取得する方法がありません。奇妙なことに、関数値型を作成することはできますが、何も代入することはできません。

Here is code snippitこれは、lambdaおよびさまざまなコールバックがテンプレートとどのように反応するかを示しています。

+0

本当に有益なコードに感謝します。 – sap

+0

これは間違っています。関数参照は正常です。もし 'Test'が' void Test(Func&callback) 'として宣言されていれば' Func'は 'void(int)'に、 'Callback'はポインタに変換されずに'テスト。 –

+0

うわー!私はそれがとても似ているので、参照はポインタだけでなくサポートされるべきだと思う。関数値を宣言して何かを割り当てることは可能ですか? –

0

C++ 11(とboostとtr1)では、関数、ラムダ、関数を格納するためのテンプレート型としてstd :: functionがあります。したがって、関数std :: functionの変数に関数の値を保持するという概念を持つことは間違いありません。その変数は、関数(参照)が格納されていないことを意味する「空」でもかまいません。その後、呼び出すことはできません。

元の質問は、Cとは対照的に、C++では関数参照が可能です。さらに、Cとの互換性の理由から、関数名を関数ポインタに縮退することができます。しかし、オーバーロードのために、C言語ではC言語よりも面白いです。

関連する問題