В качестве интересного продолжения (хотя и не имеющего большого практического значения) моего предыдущего вопроса: почему C ++ позволяет нам заключать имя переменной в круглые скобки при объявлении переменной?
Я обнаружил, что объединение объявления в круглых скобках с введенной функцией имени класса может привести к неожиданным результатам в отношении поведения компилятора.
Взгляните на следующую программу:
#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 кажется странным)
источник
C::C y;
не имеет смысла, правда? И тоже.C::C (y);
Сначала я думал, что это экземпляр Most-Vexing-Parse stackoverflow.com/questions/tagged/most-vexing-parse , но теперь я думаю, что это просто неопределенное поведение, означающее, что все три компилятора «правы».C::C
не называет тип, он называет функцию, так что GCC прав imo.Ответы:
GCC правильный, по крайней мере, в соответствии с правилами поиска C ++ 11. 3.4.3.1 [class.qual] / 2 указывает, что если описатель вложенного имени совпадает с именем класса, он относится к конструктору, а не к внедренному имени класса. Приведены примеры:
Похоже , MSVC извращает его в качестве выражения приведения функции стиля , создавая временный
C
с вy
качестве параметра конструктора; а Clang неверно интерпретирует это как объявление переменной с именемy
типаC
.источник
A::A a;
, следует игнорировать имена функций - или нет?C (B *)
" .G ++ правильный, так как выдает ошибку. Потому что конструктор не может быть вызван напрямую в таком формате без
new
оператора. И хотя ваш код вызываетC::C
, это похоже на вызов конструктора. Однако в соответствии со стандартом C ++ 11 3.4.3.1 это не законный вызов функции или имя типа ( см. Ответ Майка Сеймура ).Clang ошибочен, поскольку он даже не вызывает правильную функцию.
MSVC - это что-то разумное, но все же оно не соответствует стандарту.
источник
new
меняет оператор?new B(1,2,3)
это своего рода «прямой вызов конструктора» (что, конечно, не так), в отличие от временного экземпляраB(1,2,3)
или объявленияB b(1,2,3)
.new B(1,2,3)
такое?new
, имени типа и списка аргументов конструктора. Это все еще не «прямой вызов конструктора».C::C (y);
какC::C y;
, то есть определение переменной y типа C (с использованием введенного типа C: : C при ошибочном игнорировании все более безумной спецификации языка 3.4.1,2, которая делает C :: C конструктором). Это не такая уж явная ошибка, как вы думаете, imo.