Почему CLS () имеет разные значения в C ++ 11 - PullRequest
1 голос
/ 07 декабря 2011

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;
}

ОБНОВЛЕНИЕ 12/8/2011

Согласно C ++ 11 7.1.6.2/1, ожидаемая строка вскобка это выражение.Компилятору просто нужно проверить, может ли строка быть проанализирована как допустимое выражение.Если да, код правильно сформирован.Таким образом, для кода «decltype (CLS ()) obj1;», «CLS ()» обрабатывается как допустимое выражение, которое обозначает различие объекта.

decltype-specifier:
    decltype ( expression )

ОБНОВЛЕНИЕ 1/3/ 2012

Potatoswatter дает объяснение, почему "CLS obj2 (CLS ());"является объявлением, отличным от определения объекта.

Все, что может быть интерпретировано как выражение или объявление, является объявлением, каким бы необычным оно ни было.CLS obj2 (CLS ());объявляет функцию, чей тип параметра CLS () является функцией без аргументов, возвращающих CLS, а тип возвращаемого значения - CLS.

Ответы [ 3 ]

2 голосов
/ 07 декабря 2011

Ожидается ли: Да

Он известен как " самый неприятный анализ ".

CLS obj2(CLS());  // function forward declaration.

CLS obj2  = CLS(); // Creates object zero initialized.
CLS obj2;          // Creates object default initialized.
1 голос
/ 02 января 2012

Как уже говорили другие, это самый мучительный разбор.Все, что может быть интерпретировано как выражение или декларация, является декларацией, какой бы необычной она ни была.CLS obj2( CLS() ); объявляет функцию, тип параметра которой CLS() является функцией без аргументов, возвращающих CLS, и тип возвращаемой информации - CLS.

Например,

CLS obj2( CLS() ); // forward declaration

CLS obj2( CLS fun() ) { // definition
    return fun(); // use unusual functional argument
}

CLS foo() { // define a function to use as unusual argument
    return CLS();
}

int main() {
    CLS obj2( CLS() ); // still a forward declaration, even in this context!

    CLS x = obj2( foo );
}

Решениеиспользуйте C ++ 11 равномерную инициализацию :

CLS obj2{ CLS() };

или просто

CLS obj2{};
1 голос
/ 07 декабря 2011

В аргументе 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, это больше не работает (и для неавтоматических переменных это никогда не работало в любом случае).

...