2011-08-01 25 views
7

typedef int (&rifii) (int, int)は何のために使用されますか?C++構文/セマンティクス質問:関数とtypedefキーワードへの参照

この "文"の前にtypedefとは何ですか? は、私はそこではありません

typedef (int (&rifii) (int, int)) [new name] 

が、[新しい名前]と考えるにしたいようなあなたは、次の構文のため

typedef int INTEGER; 

同様の質問を行った場合:

typedef void (*PF)(); 

PF edit_ops[ ] = { &cut, &paste, &copy, &search }; 
PF file_ops[ ] = { &open, &append, & close, &write }; 

PF* button2 = edit_ops; 
PF* button3 = file_ops; 

button2[2](); 

何typedefは許可されていますか?

void (*PF)(); 
(void (*PF)()) edit_ops[ ] = { &cut, &paste, &copy, &search }; 
(void (*PF)()) file_ops[ ] = { &open, &append, & close, &write }; 

(void (*PF)())* button2 = edit_ops; 
(void (*PF)())* button3 = file_ops; 

ので、何がのようにtypedefでの第二の部分([あなたが望むもの])に起こった場合::あなたが入力する必要はありませんので、それはそれを作っている

typedef [what you have -- (FP)] [what you want] 

明確化についてこの問題は非常に高く評価されます。

+0

可能な複製http://stackoverflow.com/questions/1591361/understanding-typedefs-for-function-pointers-in-c-examples -hints-and-tips-plea – vines

+0

質問は似ていますが、投稿する前に関連するトピックを調べましたが、私の質問は具体的で、他の投稿から回答を推論することはできませんでした。 –

答えて

16

Typedefはtypedef [type] [new name]のように動作しません。 [new name]の部分は必ずしも最後に来るわけではありません。

[some declaration]が変数を宣言する場合、typedef [same declaration]は型を定義します。

など。: - >typedef int x; はintとしてタイプxを定義する

  • int x;はint型のxという名前の変数を宣言します。
  • struct { char c; } s;は、いくつかのstruct型のsという名前の変数を定義します。 - >typedef struct { char c; } s;は、型sをいくつかのstruct型に定義します。
  • int *p;は、int型ポインタの型pの変数を宣言します。 - typedef int *p;は、型pをintへのポインタとして定義します。

も:

  • int A[];は、名前のint型の配列を宣言 - >typedef int A[];は、int型の配列としてタイプAを宣言しています。
  • int f();は、f - >typedef int f();という名前の関数を宣言すると、関数型fがintを返し、引数をとらないと宣言します。
  • int g(int);は、関数名g - >typedef int g(int);を宣言すると、関数型gがintを返し、intを1つと宣言します。

脇に:すべての関数引数が新しい名前の後に来ることに注意してください。これらのタイプも複雑になる可能性があるため、[新しい名前]の後には多くのテキストが存在する可能性があります。残念ながら、しかし真実。

しかし、それらは適切な機能ではありませんポインタまだ、機能の種類だけです。関数型がCまたはC++に存在するかどうかはわかりませんが、説明の中間ステップとしては便利です。

実際の関数ポインタを作成するには、名前に '*'を追加する必要があります。これは、悲しいことに、間違った優先順位を持って:*int型を返すよう

  • typedef int *pf();は、関数型PFを宣言します。おっと、それは意図されたものではありません。

だから、グループに()を使用します

  • typedef int (*pf)();はint型を返すと、引数を取らないよう関数ポインタ型PFを宣言します。
  • typedef int (&rf)();は、関数参照型rfをintを返し、引数をとらないものとして宣言します。

のは、今、あなたの例を見て、あなたの質問にお答えしましょう:

typedef int (&rifii) (int, int);はint型を返すと、2つのint型の引数を取るようrifii機能の参照型を宣言します。

明らかに(?)button2[2]();copy();と呼びます。typedefなし

適切な構文は、コンパイラなしで正しく書くのは難しい、とさえコンパイラで読みにくいです:

void (*edit_ops[])() = { &cut, &paste, &copy, &search }; 
void (*file_ops[])() = { &open, &append, & close, &write }; 

void (**button2)() = edit_ops; 
void (**button3)() = file_ops; 

button2[2](); 

関数ポインタを使用しているとき、誰もがのtypedefを好む理由です。

読むときは、読む場所を見つけてください。可能な限り右に読むが、()でグループを観察する。できるだけ左に読んでください。もう一度グループ化して制限してください()。 ()内のすべてを終えたら、右に読んでから左に読んでください。 void (*edit_ops[])()に適用

、これは

  1. edit_opsは (右に行く)
  2. 配列 (グループの終わりを打つので、左に回す)
  3. のあることを意味しポインタ をとる関数(グルーピングの端)
  4. (右に()を解析)
  5. ないargume専門家のために、ボイド

を返すNTS (左へ)

  • それがさらに複雑にするために、引数は(無視されます)の名前を持つことができますので、それもあるかもしれません構文解析を開始する場所を見つけるのは難しいです!例えば。 typedef int (*fp)(int x);は有効で、typedef int (*fp)(int);と同じ名前はそれらの周りに()を持つこともできます:typedef int (*fp)(int (x));しかし、これまで見てきたように、引数名は省略できるので、次のものも許可されます:typedef int (*fp)(int());。これはまだ単一のintをとり、intを返す関数ポインタです。あなたのコードを本当に読みにくくしたい場合は...

  • +0

    あなたの説明は助けになります:typedef void(* PF)();型宣言(* PF)は、0の引数をとり、何も返さない関数ポインタとして定義されているので、ここでは、PF edit_ops [] = {などの式でこれを使うことができる場合はPF型があります。 ..}。 "新しい型"を定義することなく、void(* edit_ops [])()= {...}を使用します。これは関数ポインタの配列を作成しています。この式の型は関数ポインタですか? –

    +0

    @Matthew:はい、 'void(* edit_ops []()= {...}; 'は関数ポインタの配列を定義し、この配列を' cut'、 'paste'、' copy'、 'search'の値で初期化します。 'void(** button2)()= edit_ops;'はその配列の0番目の要素へのポインタを宣言します。 'button2 [2]();'は配列の3番目の要素を使い、それが指す関数を呼び出します。それは起こる 'コピー'。 – Sjoerd

    +0

    @Matthew:あなたの最初の文では、 'typedefは無効(* PF)は、()' ''タイプPF'、*ない* '(* PF)を宣言します。 'PF'は既にポインタです。最後の文 'void(* x [])(... =)'は 'x'を関数ポインタの配列と宣言します。 –

    -1

    編集:申し訳ありませんが最初の答えは、fcn ptrを初期化しませんでした。

    typedef int(& rifii)(int、int)は、参照としてintを返す関数ポインタを宣言し、パラメータとして2つのintを取ります。

    rifi x,y,z; 
    
    int &ret_an_int_ref(int p1, int p2) { 
        static int retval=0; 
        if(p1 > p2) retval = p1*p2; 
        return retval; 
    } 
    
        x = ret_an_int_ref; 
        y = ret_an_int_ref; 
    
    int & an_int_ref = x(1,2); 
    int & another_int_ref=y(3,4); 
    
    z = x; 
    
    z(1,2); // will give the same answer as x(1,2); 
    
    +0

    今、rifiはタイプですか?変数x、y、zはその型ですか?そしてBjarneによれば、関数からの参照を返すことは罪なので、私はこれを決して見ることはないと仮定していますか? –

    +0

    rifiが "タイプ"であるかどうかは100%確実ではありません。おそらく、熟達しているのは、タイプのように機能し、タイプのように振る舞い、おそらくテンプレートパラメータとして使われます。あなたはおそらくこれを見かけることはありませんが、複雑なデータ型の場合はrefで返すほうが良いでしょう。そしてoperator =は常にrefで返されるべきで、A = Aのようなダンプ文はsegフォールトを引き起こさない。 –

    +0

    関数はintへの参照を返しませんが、(普通の)intを返す関数への参照です。あなたのバージョンは 'typedef int&(rifii)(int、int);' – Sjoerd

    5

    これ:

    typedef int (&rifii) (int, int); 
    

    は、2つの整数値を取り、整数を返す関数であるrifiiという名前のtypedefを作成します。これは、関数typedefを宣言するためのtypedef構文です。ですから、機能している場合:

    int SomeFunc(int a, int b); 
    

    あなたはそれのtypedefでそれを保存することができます:

    rifii varName = SomeFunc; 
    

    をし、後でそれを呼び出す:だから

    varName(1, 3); 
    

    をあなたはrifiiの配列を宣言した場合、あなたが持っているのは、すべてが同じ署名を持つ関数への参照の配列です。 PFあなたのtypedefは、パラメータを取らず何も返さないポインタ関数です。したがって、これらの配列はパラメータを取らず何も返さない関数の配列です。

    基本的に、C/C++関数の名前付けが奇妙であるため、typedef名(typedefを作成する名前)は関数型の途中にあります。それは奇妙ですが、あなたはそれに慣れています。