0

私の教師の 1 人がこの型宣言を使用しています。

typedef void (*SortFunction)(int a[], int n);

関数へのポインターを保持でき、後でプログラムでその関数を呼び出すために使用できる型を作成します。

また、関数をパラメーターとして渡すには、関数名を括弧で囲み、関数名の後に関数のパラメーターを括弧で囲む必要があることも知っています。

function someFunction( (anotherfunction)(type arg1, type arg2,...)){
  ...
} 

私が知りたいのは、関数をこのように括弧で囲む必要があるのはなぜですか? これはほとんどの C++ コンパイラの組み込み関数ですか、それともコード内で関数を引数として有効にするためにプログラマが使用する単なるトリックですか? また、typedef ステートメントの「SortFunction」を参照する必要があるのはなぜですか。SortFunction を使用するために使用する変数が、関数を指すのではなく、関数を保持できないのはなぜですか?

4

4 に答える 4

1

「関数をパラメーターとして渡すには、関数名を括弧で囲む必要があることも知っています...」あなたは「知っています」が間違っています。

関数ポインターをパラメーターとして渡すために、名前を括弧で囲む必要はありません。たとえば、これは完全にうまく機能します

void foo(int i) {
} 

void bar(void f(int)) {
  f(5);
}

int main() {
  bar();
}

上記の例では、関数barは関数へのポインターをパラメーターとして受け取り、そのポインターを介してfoo呼び出し、引数としてfoo渡し5ます。ご覧のとおり f、パラメーター宣言の関数名は括弧で囲まれていません。

この場合も、明示的にポインターとして宣言されていなくても、パラメーターの型fは実際には関数へのポインターです。関数型が関数パラメーター宣言で使用されると、コンパイラーによって自動的に暗黙的に関数ポインター型に "置き換え" られます。

関数ポインター型を明示的に使用したい場合は、次のように宣言する必要がありますbar

void bar(void (*f)(int)) {
  f(5);
}

この場合、が にバインドされ、にバインドされないようにするために、 の括弧(*f)が必要です。括弧がないと、宣言は、目的の「関数を返すポインタ」ではなく、「関数を返す」を表します。*fvoidvoid *f(int)void *void

于 2012-11-12T18:52:14.393 に答える
1

関数の引数について特別なことは何もありません。関数ポインターを (ローカル変数、グローバル変数、クラス メンバー変数、関数パラメーター、typedef などとして) 宣言するときは常に、次のように宣言します。

return_type (*var_name)(T1 param1, T2 param2, /* etc. */ );
//           ^
//           |
// This * is very important!

var_name関数ポインター変数の名前はどこにありますか。括弧が必要な理由は、*var_name演算子の優先順位によるものです。括弧がないと、*(何かがポインターであることを示す) が関数の戻り値の型と一致し、代わりにint*(ポインターへのint)の戻り値の型のようなものが得られます。プレーンのint

関数は C および C++ のファースト クラス オブジェクトではないため、関数を引数として渡すことはできません。関数を渡す唯一の方法は、関数へのポインターを渡すことです。

于 2012-11-12T18:20:52.197 に答える
0

私が知りたいのは、関数をこのように括弧で囲む必要があるのはなぜですか?

コンパイラ (というよりは、パーサー) への関数ポインターを識別する何らかの方法が必要であり、その方法はどの方法よりも優れているように思えたからです。C++11 ランドでは、代わりにこれを使用できますstd::function<void(std::array<int>&)>

これはほとんどの C++ コンパイラの組み込み関数ですか、それともコード内で関数を引数として有効にするためにプログラマが使用する単なるトリックですか?

関数ポインターには少し追加の魔法が必要であり、コンパイラーのサポートがなければ、使用するのは非常に不便です。また、ほぼすべてのプログラマーのトリックが最終的にはコンパイラーの機能であることは、プログラミングの本質であることもかなり確信しています!

また、typedef ステートメントの「SortFunction」を参照する必要があるのはなぜですか。SortFunction を使用するために使用する変数が、関数を指すのではなく関数を保持できないのはなぜですか?

うーん。ここで何を意味するのか完全にはわかりません。「なぜこれがtypedefまったく必要なのですか...関数の引数に関数ポインタープロトタイプ全体を書き出せなかったのはなぜですか」という意味ですか? できること:

void foo(void(*funcptr)()) {}

「関数ポインタがコードをインラインにするのではなく関数を指す必要があるのはなぜですか」という意味であれば、そのためにはC++ 11とラムダが必要です。

#include <iostream>
#include <functional>

void foo(std::function<void(void)> bar) { bar(); }

int main(int argc, char* argv[])
{
    foo([]() { std::cout << "hi!" << std::endl; });
}

[](){}(ここでも、パーサーに何が起こっているかを伝えるために、ラムダに必要な特別な構文が必要です)

于 2012-11-12T18:41:09.643 に答える
0

それは構文の問題です。最初に、 とのベクトルを受け取り、何も返さないtypedef関数である型を定義します( )。intintvoid

タイプの変数は、 SortFunction概念的には他の変数と同じですが、何らかの関数を指しています。利点は、それが指す関数を変更したり、関数を動的に呼び出したりできることです。

于 2012-11-12T18:21:04.457 に答える