Почему CLS() имеет разные значения в C++11
-
29-10-2019 - |
Вопрос
VS2010 частично поддерживает C++11.Я компилирую приведенный ниже код в VS2010 RTM.Я не понимаю, почему код CLS() анализируется по-разному.В строке «decltype(CLS()) obj1;» CLS() обозначает объект объекта класса.Но в строке «CLS obj2(CLS());» CLS() обозначает указатель на функцию, которая перенастраивает объект CLS без параметра.Ожидается ли такое поведение?Описано ли это в стандарте?
struct CLS
{
int mi;
};
int _tmain(int argc, _TCHAR* argv[])
{
decltype(CLS()) obj1;
obj1.mi = 10;
CLS obj2(CLS());
obj2.mi = 10; // error C2228: left of '.mi' must have class/struct/union
return 0;
}
ОБНОВЛЕНИЕ 08.12.2011
В C++11 7.1.6.2/1 ожидаемая строка в скобках является выражением.Компилятору просто нужно проверить, можно ли проанализировать строку как допустимое выражение.Если да, то код правильно сформирован.Таким образом, для кода «decltype(CLS()) obj1;» «CLS()» рассматривается как допустимое выражение, обозначающее определение объекта.
decltype-specifier:
decltype ( expression )
ОБНОВЛЕНИЕ 03.01.2012
Potatoswatter дает объяснение, почему «cls obj2 (cls ());»; является объявлением, кроме определения объекта.
Все, что можно интерпретировать как выражение или объявление, является объявлением, каким бы необычным оно ни было.CLS obj2( CLS() );объявляет функцию, тип параметра которой CLS() является функцией без аргументов, возвращающей CLS, и тип возвращаемого значения — CLS.
Решение
Как уже говорили другие, это самый неприятный синтаксический анализ.Все, что может быть интерпретировано как выражение или объявление, является объявлением, каким бы необычным оно ни было.CLS obj2( CLS() );
объявляет функцию, тип параметра которой CLS()
- это функция без аргументов, возвращающая CLS, и тип возвращаемого значения - CLS.
Например,
родовое словоРешение состоит в использовании равномерной инициализации C ++ 11 :
родовое словоили просто
родовое словоДругие советы
Ожидается: Да
Это известно как « Самый неприятный разбор ".
CLS obj2(CLS()); // function forward declaration.
CLS obj2 = CLS(); // Creates object zero initialized.
CLS obj2; // Creates object default initialized.
. В аргументе decltype
, ожидается выражение.Единственный способ интерпретации CLS()
как выражение состоит в том, чтобы проанализировать его как созданный по умолчанию объект типа CLS
.
Однако в CLS obj2(CLS())
(который, кстати, работает так же в C++03) есть два возможные разборы:Один как объявление функции и один как определение объекта.В качестве объявления функции внешние круглые скобки образуют список параметров, и ожидается, что содержимое укажет параметр (или их список), указав типы и необязательные имена.В этом анализе CLS() интерпретируется как тип функции.
Другой допустимый синтаксический анализ — это определение объекта.Для этого анализа, конечно, в скобках должно быть выражение (или их список), дающее интерпретацию CLS()
как объект типа, созданный по умолчанию CLS
.
Теперь в C++ есть правило: если что-то можно разобрать и как объявление, и как определение, оно будет анализироваться как объявление.То есть в данном случае будет использована первая интерпретация.
Это, конечно, порождает вопрос о почему первая интерпретация выбирается тогда, когда мы явно ожидаем здесь вторую.И ответ в том, что в противном случае это нарушит совместимость с C (а в некоторых случаях даже наши ожидания).Например, посмотрите на следующую строку:
int f();
Теперь вы согласитесь, что здесь объявляется функция, не принимающая аргументов и возвращающая int
, верно?Но его также можно проанализировать как определение инициализированной по умолчанию переменной типа int
.Благодаря упомянутому выше правилу оно действительно объявляет функцию, возвращающую int
.
Правило, которое всегда дает ожидаемый результат, в лучшем случае было бы сложным, но, скорее всего, невозможным.
Обратите внимание, что в C++03 простой способ избежать этого для автоматических переменных заключался в добавлении к определению префикса auto
:Поскольку объявления функций никогда не начинаются с auto
, это заставило бы компилятор интерпретировать его как определение переменной.Поскольку старое значение auto
был удален в C++11, это больше не работает (а для неавтоматических переменных оно все равно никогда не работало).