20

私のようなほとんどの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レガシーですか、それとも私が気付いていないより深いユースケースがありますか?

非信者のための編集:関数ポインタ宣言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は文句を言う:

エラー:割り当てで「void()()」を「void()()」に変換できません

コモー:

エラー:式は変更可能な左辺値である必要があります
4

7 に答える 7

13

私が考えることができる唯一の用途は、関数宣言のスコープを縮小することです:

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

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

void doSomething()
{
    ...
}

もちろん、これにはもっと良い解決策があります。関数を非表示にする必要がある場合は、関数を別のモジュールに移動してコードを再構築し、非表示にする関数を呼び出す必要がある関数がすべて同じモジュールに含まれるようにする必要があります。次に、その関数を静的に宣言する (C の方法) か、匿名の名前空間内に配置する (C++ の方法) ことによって、その関数をモジュール ローカルにすることができます。

于 2009-06-23T19:42:44.637 に答える
2

私が見ることができる唯一の正しい使用法は、コンパイルユニット内の1つの関数だけが、別のコンパイルユニットで定義された関数について認識できるようにすることです。それはやや合理的な使い方だと思いますが、私が考えることができるのはそれだけであり、それはやり過ぎだと思います。

于 2009-06-23T20:06:15.073 に答える
2

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

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

于 2009-06-24T12:26:48.033 に答える
2

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

于 2009-06-23T19:28:06.337 に答える
1

この回答の 3 番目のスニペットで述べたように、スコープ シャドウイングに役立ちます。

#include <stdio.h>

void c(); // Prototype of a function named ``c''

int main() {

    c(); // call the function

    { // additional scoppe needed for C, not for C++
        int c = 0; // shadow the c function with a c integer variable
        c++;
        {
            void c(); // hide the c integer variable back with the c function
            c();
        }
        ++c;
    } //!

    return 0;
}

void c() {
    printf("Called\n");
}

この使用法が頻繁に役立つとは思わず、適切に設計されたプログラムでは発生しない可能性があります。

私はまだこれがその機能の最も可能性の高い理由だと思います.変数のように最近関数を定義することは正しく聞こえません.

于 2012-01-11T15:34:41.813 に答える
1

変数を最初に使用する直前に (それより前ではなく) 宣言することが推奨されているのと同じ理由で、私は時々そうします。つまり、可読性を向上させるためです。(はい、変数の場合は、最初の使用であると考える前に変数が使用されているかどうかを確認する必要がなくなるため、より重要であることがわかります)。c()関数呼び出しの近くにプロトタイプを配置すると (特に、単なる よりも複雑な場合)、読みやすさが向上します。特殊なケースC c()が人間に誤解を与えるという事実は残念ですが、関数をローカルで宣言するという一般的な考え方にはメリットがあります。

もちろん、これは既にスコープ内にある関数名にも当てはまります。すべての関数を使用する前に再宣言しないのはなぜですか? それに対する私の答えは、すべてのことを適度に行うことです。混乱が多すぎると、読みやすさが損なわれます (また、関数のシグネチャが変更された場合の保守性も損なわれます)。そのため、ルールを作成するつもりはありませんが、関数をローカルで宣言すると便利な場合があります。

于 2009-06-24T06:38:41.537 に答える
-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;
}
于 2009-06-23T20:23:07.613 に答える