Изначальная нулевая инициализация с g++
Я столкнулся с странным поведением следующего кода, играя с инициализацией int с помощью g++ 4.4.3.
int main()
{
int x(int());
int y = int();
cout << x << " " << y << endl;
}
результат:
1 0
Значение "y" равно 0, как ожидалось, но значение x странно "1"!
В VS2008 приведена следующая ошибка ссылки (объявление функции, но без определения):
unresolved external symbol "int __cdecl x(int (__cdecl*)(void))"
Может ли кто-нибудь объяснить это странное поведение g++?
Ответы
Ответ 1
Чтобы дополнить ответ GMan здесь (x
- это определение функции), почему 1
.
Причиной вывода 1
является то, что в месте вызова std::cout << x
функция распадается на указатель на функцию (язык не позволяет передавать функции в качестве аргументов другим функциям, поэтому как и с массивами, выполняется неявное преобразование в указатель-к). Теперь нет перегрузки ostream
, которая принимает указатель на функцию, и компилятор пытается выбрать преобразование в любую из доступных перегрузок. В этот момент он находит, что лучшая последовательность преобразования равна bool
, и она печатает 1
(указатель не равен 0).
Вы можете проверить это, изменив поведение, вы можете использовать std::cout << std::boolalpha << x
, и он будет печатать true
вместо 1
. Кроме того, интересно отметить, что VS является правильным с этим, так как выражение std::cout << x
требует ввода адреса x
, тогда функция используется, и программа плохо сформирована, если нет определения для этой функции, Вы можете снова проверить это, предоставив определение:
int f() {}
int main() {
int x(int()); // 1
x( &f ); // 2
}
int x( int(*)() ) { // 3
std::cout << "In x" << std::endl;
}
Где я вручную выполнил преобразование из function
в pointer-to-function
в определение x
(1), а вызов с аргументом f
(2) - отметьте, что объявление в 1 и определение в 3 является одной и той же сигнатурой и что &
in x( &f )
будет выполняться компилятором, если вы этого не сделаете.
Ответ 2
int x(int());
анализируется как объявление функции.
Он объявляет функцию с именем x
, возвращая int
и принимающий один параметр, который имеет тип функции, возвращающей int
и не принимающий аргументов.
Это называется самым неприятным анализом.
Ответ 3
Просто добавьте больше parens:
int main()
{
int x((int()));
int y = int();
cout << x << " " << y << endl;
}
Теперь x - это int, а не функция.
Ответ 4
Как говорили другие, x
- это объявление функции. Поскольку для типов указателей функций не существует предопределенного встраивания ostream, g++, похоже, использует неявное преобразование bool (используемое для проверки, является ли указатель функции NULL), чтобы найти способ его вывода.
Visual С++, с другой стороны, жалуется, что объявленная функция x
никогда не определена и, следовательно, не может завершить связь. Я подозреваю, что g++ в этом случае достаточно умен, чтобы видеть, что функция никогда не вызывается, и поэтому не беспокоится о ссылке.
Вы можете попробовать добавить фиктивное определение функции int x(int(*)()) { return 0xdeadbeef; }
к коду и посмотреть, что с ним делает MSVC.
Ответ 5
С++ интерпретирует первый как объявление функции.
Ответ 6
Это
int x(int());
Является фактически объявлением функции, вход является функцией следующей подписи
int fn(void)
Указатель функции, переданный в std::cout <<
, преобразуется в bool (1), поскольку это не-NULL-указатель.