Конструктор по умолчанию с пустыми скобками
Есть ли веская причина, по которой пустой набор круглых скобок (скобок) недопустим для вызова конструктора по умолчанию в C++?
MyObject object; // ok - default ctor
MyObject object(blah); // ok
MyObject object(); // error
Кажется, я пишу "()" автоматически каждый раз. Есть ли веская причина, по которой это не разрешено?
9 ответов
Самый неприятный разбор
Это связано с тем, что известно как "самый неприятный синтаксический анализ C++". По сути, все, что может быть интерпретировано компилятором как объявление функции, будет интерпретировано как объявление функции.
Еще один пример той же проблемы:
std::ifstream ifs("file.txt");
std::vector<T> v(std::istream_iterator<T>(ifs), std::istream_iterator<T>());
v
интерпретируется как объявление функции с 2 параметрами.
Обходной путь должен добавить другую пару круглых скобок:
std::vector<T> v((std::istream_iterator<T>(ifs)), std::istream_iterator<T>());
Или, если у вас есть C++11 и инициализация списка (также известная как равномерная инициализация):
std::vector<T> v{std::istream_iterator<T>{ifs}, std::istream_iterator<T>{}};
При этом никоим образом это не может быть интерпретировано как объявление функции.
Потому что это рассматривается как объявление для функции:
int MyFunction(); // clearly a function
MyObject object(); // also a function declaration
Тот же синтаксис используется для объявления функции - например, функция object
без параметров и возврата MyObject
Потому что компилятор считает, что это объявление функции, которая не принимает аргументов и возвращает экземпляр MyObject.
Вы также можете использовать более подробный способ построения:
MyObject object1 = MyObject();
MyObject object2 = MyObject(object1);
В C++0x это также позволяет auto
:
auto object1 = MyObject();
auto object2 = MyObject(object1);
Я думаю, компилятор не будет знать, если это утверждение:
Объект MyObject ();
является вызовом конструктора или прототипа функции, объявляющей функцию с именем object с возвращаемым типом MyObject и без параметров.
Как уже много раз упоминалось, это декларация. Это способ обратной совместимости. Одна из многих областей C++, которые являются глупыми / противоречивыми / болезненными / поддельными из-за своего наследия.
От n4296 [dcl.init]:
[ Заметка:
поскольку()
не допускается синтаксисом для инициализатора,X a();
не является объявлением объекта класса X, но объявлением функции, не принимающей аргументов и возвращающей X. Form () разрешена в некоторых других контекстах инициализации (5.3.4, 5.2.3, 12.6.2).
—Конечная записка]
Как говорили другие, это объявление функции. Начиная с C++11 вы можете использовать фигурную инициализацию, если вам нужно увидеть пустое что-то, что явно говорит вам об использовании конструктора по умолчанию.
Jedi luke{}; //default constructor