Поведение decltype

Скажем, у меня есть объект некоторых классов контейнеров stl obj. Я могу определить другой объект такого же типа следующим образом:

decltype(obj) obj2;

Но я не могу объявить итератор для контейнера следующим образом:

decltype(obj)::iterator it = obj.begin();

Почему? Я что-то делаю неправильно?

Ответ 1

Ваш код хорошо сформирован в соответствии с окончательным проектом С++ 0x (FDIS). Это было последнее изменение, которое еще не было реализовано компилятором Visual Studio.

В то же время обходным путем является использование typedef:

typedef decltype(obj) obj_type;
obj_type::iterator it = obj.begin();

EDIT: Соответствующая глава и стих 5.1.1/8:

qualified-id:
    [...]
    nested-name-specifier templateoptunqualified-id

nested-name-specifier:
    [...]
    decltype-specifier ::

decltype-specifier:
    decltype ( expression )

И ради полноты:

Исходная основная проблема

Предложение для формулировки

Ответ 2

Это из-за того, как язык анализируется.

decltype(obj)::iterator it = obj.begin();

Вы хотите, чтобы он стал

(decltype(obj)::iterator) it;

Но на самом деле он становится

decltype(obj) (::iterator) it;

Я должен признать, я был также удивлен, увидев, что это так, поскольку я уверен, что я сделал это раньше. Однако в этом случае вы можете просто использовать auto или даже decltype(obj.begin()), но, кроме того, вы можете сделать

typedef decltype(obj) objtype;
objtype::iterator it;

Ответ 3

Еще одно обходное решение до тех пор, пока синтаксический анализатор VС++ не будет зафиксирован для отражения FDIS, заключается в использовании метафайла std::identity<>:

std::identity<decltype(obj)>::type::iterator it = obj.begin();