Декларатори функцій C
Перш за все, існує C. В C - A a()
це оголошення функції. Наприклад, 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());
Один аргумент у конструкторі
Ви цього не впізнаєте? Ну, нагадаю.
A a(B());
Так, це саме те саме оголошення функції. A
є int
, a
є output_result
і B
є int
.
Ви можете легко помітити конфлікт C за допомогою нових функцій C ++. Якщо бути точним, конструктори мають назву класу та круглі дужки та чергують синтаксис декларації з ()
замість =
. За задумом C ++ намагається бути сумісним із кодом С, а тому йому доводиться мати справу з цією справою - навіть якщо практично нікого не цікавить. Тому старі функції C мають пріоритет перед новими функціями C ++. Граматика декларацій намагається відповідати імені як функції, перед тим як повернутися до нового синтаксису, ()
якщо воно не вдалося .
Якщо одна з цих функцій не існувала б або мала інший синтаксис (як, наприклад, {}
у C ++ 11), ця проблема ніколи не сталася б для синтаксису з одним аргументом.
Тепер ви можете запитати, чому 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
).
Більше аргументів у конструкторі
Безумовно, один аргумент приємний, але як бути два? Справа не в тому, що у конструкторів може бути лише один аргумент. Один із вбудованих класів, який бере два аргументи, це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>::
^
Я не знаю , чому г намагається ++ перетворити char
в const char *
. Так чи інакше, конструктор викликався лише одним значенням типу char
. Немає перевантаження, яка має один аргумент типу char
, тому компілятор плутається. Ви можете запитати - чому аргумент має тип char?
(100, '.')
Так, ,
ось оператор з комами. Оператор з комами приймає два аргументи та надає правий аргумент. Це насправді не корисно, але моє пояснення має бути відомим.
Натомість, щоб вирішити найбільш неприємний синтаксис, потрібен наступний код.
std::string hundred_dots((100), ('.'));
Аргументи є в дужках, а не в усьому виразі. Насправді, лише один із виразів повинен бути в дужках, оскільки для використання функції C ++ достатньо трохи відірватися від граматики С. Речі доводять нас до точки нульових аргументів.
Нульові аргументи в конструкторі
Можливо, ви помітили цю eighty_four
функцію в моєму поясненні.
int eighty_four();
Так, на це впливає і найприємніший розбір. Це правильне визначення, і це ви, швидше за все, бачили, якщо ви створювали файли заголовків (і вам слід). Додавання дужок це не виправить.
int eighty_four(());
Чому це так? Ну, ()
це не вираз. У C ++ ви повинні ставити вираз між дужками. Ви не можете писати auto value = ()
на C ++, тому що ()
нічого не означає (і навіть якби це було, як порожній кортеж (див. Python), це був би один аргумент, а не нуль). Це практично означає, що ви не можете використовувати скорочений синтаксис без використання синтаксису C ++ 11 {}
, оскільки в дужках немає виразів, а граматика C для декларацій функцій завжди застосовуватиметься.
(B())
це лише вираз C ++, не більше того. Це не будь-який виняток. Єдина відмінність, яку він робить - це те, що немає можливості його розібрати як тип, і так це не так.