web-dev-qa-db-ja.com

関数定義で仮引数名のないC ++コードが警告なしにコンパイルされるのはなぜですか?

VS2005で生成されたMFCコードを使い始めたところ、次のようなメソッドでメソッドが上書きされていることに気付きました。

void OnDraw(CDC* /*pDC*/)
{
    ...
    // TODO: Add your code here
}

もちろん、何かを追加するとすぐに、コンパイルするためにpDC仮引数のコメントを外す必要があることに気付きましたが、C++関数が(警告なしで)コンパイルできる方法/理由について、混乱しています。引数には型のみがあり、名前はありません:

void foo(int)
{
    int x = 3;
}
int main()
{
    foo(5);
    return 0;
}

これは少なくとも警告を生成するべきではありません(-Wallまたは/ W4を使用)。ないようです。何か不足していますか?行が処理されるまで、コンパイラーが関数宣言(型のみが必要)と定義(完全に指定されている)の違いを区別できないため、これが役立つ場合はありますか?

47
Andrew Coleson

インターフェースに必要なパラメータがある場合がありますが、関数はそれを使用しません。パラメータが不要になったか、同じシグネチャを使用する必要がある他の関数(特にポインタを介して呼び出すことができるため)でのみ必要か、または機能がまだ実装されていない可能性があります。この理由により、生成されたコードやフレームワークコードでは、使用されないパラメーターがあることは特に一般的です(MFCで生成されたコードの名前がコメント化されているのはそのためです)。

なぜ警告がないのか-これが問題であるかどうかは主観的なものであり、他の人々(特にコンパイラの実装者)はそれを問題と見なしていないためだと思います。実際にパラメーターを使用すると、名前のコメントを外すのを忘れた場合にコンパイラーが文句を言うので、本当に必要な場合にのみコンパイラーが文句を言うことになります(コンパイラーのアジャイルYAGNIのバージョン: "You Aren ' t Gonna Neet It」の哲学)。

警告-使用されない名前付きパラメーターが警告を生成する場合-通常、反対のことが発生するように思われます。これも、生成された関数の名前がコメント化されている理由です。

53
Michael Burr

私が見た最も一般的な理由は、コンパイラがスローする未使用の変数警告を抑制するためです:

_#include <iostream>

void foo(int source)
{
  std::cout << "foo()" << std::endl;
}

int main()
{
  foo(5);
  return 0;
}
_

gccさんのコメント:_main.cc:3: warning: unused parameter 'source'_

警告を取り除くには、2つの一般的な方法があります。変数名をコメントにするか、完全に削除します。

_void foo(int /*source*/)
{
  std::cout << "foo()" << std::endl;
}
_

versus

_void foo(int)
{
  std::cout << "foo()" << std::endl;
}
_

削除するよりもコメントすることを強くお勧めします。そうでない場合、メンテナンスプログラマは、そのパラメータが他の方法で何を表しているのかを見つける必要があります。

Qt(およびおそらく他のフレームワーク)は、変数名をコメント化または削除する必要なしに警告を抑制するマクロを提供します:Q_UNUSED(<variable>)

_void foo(int source)
{
  Q_UNUSED(source); // Removed in version 4.2 due to locusts
  std::cout << "foo()" << std::endl;
}
_

これにより、変数が使用されていないことを関数本体で呼び出すことができ、ドキュメント化するのに最適な場所になりますwhy使用されません。

17
Bill

C++ 11 N3337標準ドラフト

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf 8.4.1/6で合法であると述べている「関数の定義>一般":

注:未使用のパラメーターに名前を付ける必要はありません。例えば、

void print(int a, int) {
    std::printf("a = %d\n",a);
}

より正確には、8.4.1/1は関数定義の文法は

function-definition:
    attribute-specifier-seqopt decl-specifier-seqopt
    declarator virt-specifier-seqopt function-body

次に、文法の定義に従うと、 「Annex A Grammar summary」の下に、名前がオプションであることが表示されます。

言語標準ではコンパイルする必要があると明確に規定されているため、コンパイルされます。他に答えはありません。これは、C++をCと区別するビットの1つです。Cでは、関数定義のパラメーター名が存在する必要があり、C++ではオプションです。

なぜ「なぜ」の質問をするのだろう。この動作に不自然な、異常な、または非論理的な何かを見ますか?

2
AnT