C関数宣言子
まず、CがA a()
あります。Cには関数宣言があります。たとえばputchar
、次の宣言があります。通常、そのような宣言はヘッダーファイルに格納されますが、関数の宣言がどのように見えるかを知っていれば、それらを手動で記述することを妨げるものはありません。引数名は宣言ではオプションであるため、この例では省略しています。
int putchar(int);
これにより、このようなコードを記述できます。
int puts(const char *);
int main() {
puts("Hello, world!");
}
Cでは、関数を引数として取る関数を定義することもできます。関数呼び出しのように見える読みやすい構文を使用できます(関数へのポインターを返さない限り、読みやすいです)。
#include <stdio.h>
int eighty_four() {
return 84;
}
int output_result(int callback()) {
printf("Returned: %d\n", callback());
return 0;
}
int main() {
return output_result(eighty_four);
}
先に述べたように、Cではヘッダーファイルで引数名を省略できるため、ヘッダーファイルでoutput_result
は次のようになります。
int output_result(int());
コンストラクターの1つの引数
分かりませんか?さて、思い出させてください。
A a(B());
はい、それはまったく同じ関数宣言です。A
is int
、a
is output_result
、B
is int
です。
CとC ++の新機能との競合に簡単に気付くでしょう。正確には、コンストラクタはクラス名と括弧であり、代わりにを使用した宣言構文()
です=
。設計上、C ++はCコードとの互換性を維持しようとするため、実際には誰も気にしない場合でも、このケースに対処する必要があります。したがって、古いC機能が新しいC ++機能よりも優先されます。宣言の文法は、()
失敗した場合に新しい構文に戻る前に、名前を関数として照合しようとします。
これらの機能の1つが存在しないか、または異なる構文({}
C ++ 11など)があった場合、この問題は1つの引数を持つ構文では発生しませんでした。
次に、なぜA a((B()))
機能するのかを尋ねます。さて、output_result
無駄な括弧で宣言しましょう。
int output_result((int()));
動作しません。文法では、変数が括弧で囲まれていないことが必要です。
<stdin>:1:19: error: expected declaration specifiers or ‘...’ before ‘(’ token
ただし、C ++はここでは標準式を想定しています。C ++では、次のコードを記述できます。
int value = int();
そして次のコード。
int value = ((((int()))));
C ++は、Cが期待する型とは対照的に、括弧内の式が...表現であると期待します。括弧はここでは何も意味しません。ただし、無用な括弧を挿入することにより、C関数宣言は一致せず、新しい構文を適切に一致させることができます(これは、などの式を期待しているだけです2 + 2
)。
コンストラクターの引数が増えました
確かに1つの議論はいいですが、2つはどうですか?コンストラクタに引数が1つしかないことはありません。2つの引数を取る組み込みクラスの1つはstd::string
std::string hundred_dots(100, '.');
これはすべて問題なく機能します(技術的には、と記述した場合、最も厄介な構文解析になりますstd::string wat(int(), char())
が、正直に言うと誰がそれを記述しますか?しかし、このコードには厄介な問題があると仮定しましょう。括弧内のすべて。
std::string hundred_dots((100, '.'));
まったくそうではありません。
<stdin>:2:36: error: invalid conversion from ‘char’ to ‘const char*’ [-fpermissive]
In file included from /usr/include/c++/4.8/string:53:0,
from <stdin>:1:
/usr/include/c++/4.8/bits/basic_string.tcc:212:5: error: initializing argument 1 of ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ [-fpermissive]
basic_string<_CharT, _Traits, _Alloc>::
^
G ++試行を変換するために、なぜ私はわからないchar
しconst char *
。どちらの方法でも、コンストラクターはtypeの値を1つだけ使用して呼び出されましたchar
。typeの1つの引数を持つオーバーロードはないchar
ため、コンパイラーは混乱します。あなたは尋ねるかもしれません-なぜ引数はchar型ですか?
(100, '.')
はい、,
ここにコンマ演算子があります。コンマ演算子は2つの引数を取り、右側の引数を指定します。実用的ではありませんが、私の説明で知っておくべきことです。
代わりに、最も厄介な解析を解決するには、次のコードが必要です。
std::string hundred_dots((100), ('.'));
引数は括弧内にあり、式全体ではありません。実際、C ++機能を使用するには、Cの文法から少し外れるだけで十分なので、式の1つだけを括弧で囲む必要があります。物事は議論のゼロのポイントに私たちをもたらします。
コンストラクターの引数がゼロ
eighty_four
私の説明でその機能に気づいたかもしれません。
int eighty_four();
はい、これは最も厄介な解析の影響も受けます。これは有効な定義であり、ヘッダーファイルを作成した場合(および作成した場合)に見た可能性が最も高い定義です。括弧を追加しても修正されません。
int eighty_four(());
どうしてこんなことに?まあ、()
表現ではありません。C ++では、括弧の間に式を入れる必要があります。auto value = ()
C ++で書くことはでき()
ません。何も意味しないからです(そして、空のタプル(Pythonを参照)のようにそうしたとしても、ゼロではなく1つの引数になります)。実際には{}
、括弧に入れる式がないため、C ++ 11の構文を使用せずに省略構文を使用できず、関数宣言のC文法が常に適用されます。
(B())
は単なるC ++式です。例外ではありません。唯一の違いは、型として解析できる可能性がないことです。そうではありません。