Программа скомпилирована по-разному в трех основных компиляторах на С++. Какой из них прав?
Как интересное продолжение (не большое практическое значение) к моему предыдущему вопросу:
Почему С++ позволяет нам окружать имя переменной в круглых скобках при объявлении переменной?
Я выяснил, что объединение объявления в круглых скобках с введенным именем класса может привести к неожиданным результатам относительно поведения компилятора.
Взгляните на следующую программу:
#include <iostream>
struct B
{
};
struct C
{
C (){ std::cout << "C" << '\n'; }
C (B *) { std::cout << "C (B *)" << '\n';}
};
B *y = nullptr;
int main()
{
C::C (y);
}
-
Компиляция с g++ 4.9.2 дает мне следующую ошибку компиляции:
main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive]
-
Он успешно компилируется с MSVC2013/2015 и печатает C (B *)
-
Он успешно компилируется с clang 3.5 и печатает C
Итак, обязательный вопрос: какой из них прав?:)
(Я сильно склонялся к версии clang, хотя и способ msvc, чтобы остановить объявление переменной после простого изменения типа с технически его typedef кажется странным)
Ответы
Ответ 1
GCC корректен, по крайней мере, согласно правилам поиска С++ 11. 3.4.3.1 [class.qual]/2 указывает, что если вложенный спецификатор имени совпадает с именем класса, он ссылается на конструктор, а не на имя введенного класса. Он дает примеры:
B::A ba; // object of type A
A::A a; // error, A::A is not a type name
struct A::A a2; // object of type A
Похоже, что MSVC неправильно истолковывает это как выражение выражения стиля функции, создавая временный C
с y
как параметр конструктора; и Кланг неправильно истолковывает это как объявление переменной с именем y
типа C
.
Ответ 2
g++ корректен, поскольку он дает ошибку. Поскольку конструктор не может быть вызван непосредственно в таком формате без оператора new
. И хотя ваш код вызывает C::C
, он выглядит как вызов конструктора. Однако, согласно стандарту С++ 11 3.4.3.1, это не вызов юридической функции или имя типа (см. Ответ Майка Сеймура).
Clang неверен, так как он даже не вызывает правильную функцию.
MSVC - это нечто разумное, но все же оно не соответствует стандарту.