2009-06-23 10 views
19

ほとんどのC++プログラマはいくつかの点で、次のミスを犯しています。エラーはかなり明白である間、あなたはそれを知っていればローカル関数宣言のこの種のいずれかの賢明な利用がある場合ローカル関数宣言には何も使用されていますか?私のような

class C { /*...*/ }; 

int main() { 
    C c();  // declares a function c taking no arguments returning a C, 
      // not, as intended by most, an object c of type C initialized 
      // using the default constructor. 
    c.foo(); // compiler complains here. 

    //... 
} 

は今、私は思っていましたあなたがそれを行うことができることを除いて - 特にへの道がないので、同じブロック内のそのようなローカル関数を定義する。他の場所で定義する必要があります。

私は、Javaスタイルのローカルクラスは、私が頻繁に使用する傾向があるかなり良い機能、特に匿名の並べ替えだと思います。ローカルのC++クラス(インラインで定義されたメンバ関数を持つことができます)でもいくつかの使い方があります。しかし、定義のないこのローカル関数宣言は、私にとっては非常に扱いにくいようです。それはちょうどC-legacyですか、それとも私が気づいていないより深いユースケースですか?非信者のための

編集は:C c()は、関数ポインタの宣言ではありません。

このプログラム

int main() 
{ 
    void g(); 
    cout << "Hello "; 
    g(); 
    return 0; 
} 

void g() 
{ 
    cout << "world." << endl; 
} 

出力Hello world.

void fun() 
{ 
    cout << "world." << endl; 
} 

int main() 
{ 
    void g(); 
    g = fun; 
    cout << "Hello "; 
    g(); 
    return 0; 
} 

がコンパイルされません。このプログラム。 gccが文句を言う:

error: cannot convert 'void()()' to 'void()()' in assignment

コモー:

error: expression must be a modifiable lvalue
+0

GCCのエラーメッセージは間違っていることに注意してください(既知のバグ)。 "error:void() 'を代入で' void() 'に変換することはできませんが、実際にはtype-idを間違ってデマングルします。 ( "void()"の代わりに、関数(不正な型)を返す関数であれば、 "void()"と言うべきです) –

+0

関連する質問:http://stackoverflow.com/questions/928992/nested -functions-not-allowed-but-why-nested-function-prototypes-are-allowed –

+0

gccのエラーメッセージがバグであるかどうかわかりません - 実際には、 'void * g()'は 'void *'を返す関数であり、 'void(* g)()'は関数へのポインタであるのに対し、あなたは関数ポインタを扱うときに必要な 'void(g)よく、 'void()()'、つまり引数を取らず何も返さないということです。 – Tobias

答えて

2

他の関数に引数として渡したいときに、Cでローカル関数宣言をしたかったのです。私は他の言語でこれをいつもしています。その理由は、データ構造の実装をカプセル化するためです。

など。私はいくつかのデータ構造を定義します。ツリーやグラフを作成することはできません。その内部実装の詳細を公開したくはありません。私はそれを変更したり変更したりすることができます。そこで、その要素にアクセサー関数とミューテータ関数を公開し、要素を反復処理するトラバーサル関数を公開します。トラバーサル関数は、引数として要素上で動作する関数を持ちます。トラバーサル関数のタスクは、各要素に対して引数関数を実行し、場合によっては結果を何らかの方法で集約することです。トラバース関数を呼び出すと、引数関数は通常、ローカル状態に依存する特殊な演算であるため、ローカル関数として定義する必要があります。ローカル状態を含む変数、グローバル変数、またはそれらを保持するために特別に作成された内部クラスに関数をプッシュする必要があります。しかし、これは私がCとJavaで持っている問題であり、C++では問題ではありません。

+0

OK、それはCの目的を失ったCの遺産であると言っていますか? – Tobias

+0

正確ではありません。私は実際にこの状況にどのように対処するのかを知るために、テンプレートの有無にかかわらず、C++で十分な経験はありません。イテレータはC++でよく使われますが、引数として関数を使うトラバーサルメソッドについては、私はそれほど確かではありません。 – reinierpost

+0

更新:http://stackoverflow.com/questions/2116128/easier-way-to-do-callbacks-for-vectors-or-maybe-something-else-in-the-stl-c – reinierpost

2

それは前方宣言のプロトタイプです。おそらく、あなたが定義の順序に反して互いに呼び出すローカル関数やローカル関数がたくさんある場合は、それが必要かもしれません。

+0

私はここであなたのことを理解していません:あなたのユースケースでは、ソースファイルの最初に(あるいは何らかのプライベートヘッダーに)すべての関数を宣言するだけです幸いに離れて実装します。なぜ、他の関数の中に関数を1つ宣言したいのですか? – Tobias

10

私は考えることができる唯一の使用は、関数宣言のスコープを減らすことです。もちろん

int main() 
{ 
    void doSomething(); 
    doSomething(); 
    return 0; 
} 

void otherFunc() 
{ 
    doSomething(); // ERROR, doSomething() not in scope 
} 

void doSomething() 
{ 
    ... 
} 

、これにも優れたソリューションがあります。関数を隠す必要がある場合は、関数を別のモジュールに移動してコードを再構成して、非表示にする関数を呼び出す必要のある関数がすべて同じモジュール内にあるようにする必要があります。次に、その関数をstatic(C言語)または匿名名前空間(C++言語)の中に入れることで、その関数をモジュールローカルにすることができます。

2

私が見ることができるのは、別のコンパイル単位で定義されている関数についてコンパイル単位の1つの関数だけが知っていることです。私はそれがやや妥当な使用だと思うが、それは私が考えることができる唯一のものであり、それは過剰なものだと思う。

+0

しかし、(関数定義の外ではなく、ヘッダ内で)別の関数の定義の中で関数を宣言するのはなぜですか? – Tobias

+1

私が言ったように、その機能だけがそれを見ることができるように。 –

-1

パラメータを使用せずに関数を宣言してから、デフォルトのデストラクタでクラスをインスタンス化するときには、かっこをスキップします。

class C 
{ 
    public: 
    void foo() {} 
}; 


int main() 
{ 
    // declare function d, taking no arguments, returning fresh C 
    C d(); 

    // instantiate class (leave parenthesis out) 
    C c; 
    c.foo(); 

    // call declared function 
    C goo = d(); 

    return 0; 
} 

C d() 
{ 
    C c; 
    // .. 
    return c; 
} 
+1

私の質問は、オブジェクトをインスタンス化する方法ではありません、私の質問は、あなたがそれを(mainの外で宣言するのではなく)あなたがしたように宣言するのはなぜですか? – Tobias

0

私は時々、私たちは読みやすさを向上させるために、すなわち、(以前とない)右の彼らの最初の使用前に変数を宣言することが奨励されているのと同じ理由のためにそれを行います。 (はい、変数については、その変数が最初に使用される前に使用されているかどうかをチェックする必要がなくなるため、変数にとってはより重要です)。関数呼出しに近いプロトタイプ(特に、それがちょうどc()よりも関わっている場合)を持つことにより、読みやすさが向上します。特別なケースC c()が人間に誤解を招くという事実は残念ですが、機能をローカルに宣言するという一般的な考え方にはメリットがあります。

もちろん、すでにスコープ内にある関数名についても同様です。なぜ毎回すべての機能を再宣言しないのですか?それに対する私の答え:すべてのことをやり直してください。あまりにも多くの乱雑さは可読性を損なう(保守性と同様に、関数のシグネチャが変わった場合)。したがって、私はそれからルールを作成しませんが、関数をローカルで宣言すると便利なことがあります。

+0

あなたはそれをやったことがありますか?今までこれをしてきた人を知っていますか?私はそうではありません。_real_worldの例にリンクすることができれば素晴らしいでしょう。これは本当に興味深いでしょう。 – Tobias

+0

私は実際にそれを1回か2回行うという曖昧な思い出を持っていますが、特定のインスタンスを覚えていません。私が呼び出すほとんどの関数はクラスメソッドなので、それはかなり稀です。 – Ari

1

this answerの3番目のスニペットと同様、スコープシャドウイングに役立ちます。

私はこの使用法はしばしば有用であるとは思わないし、うまく設計されたプログラムでは起こらない可能性があります。

私はまだこれがその機能のもっともらしい理由だと思っています。最近、変数を定義する機能はちょうど正しいとは言えません。

関連する問題