C ++ 11 decltype
возвращает тип выражения, данного ему (в основном). Но это может отличаться от типа выражения, поскольку оно действительно доступно:
template<typename T>
struct Ref {
Ref(T&) { }
};
#define GETTYPE decltype
//#define GETTYPE typeof
struct Problem {
void doit_c() const { Ref<GETTYPE(n)> rn{n}; }
void doit_nc() { Ref<GETTYPE(n)> rn{n}; }
int n;
};
int main() {
int i;
const int ci = 0;
Problem pr;
// decltype == typeof == int
Ref<GETTYPE(i)> ri{i};
pr.doit_nc();
// decltype == typeof == const int
Ref<GETTYPE(ci)> rci{ci};
Ref<GETTYPE(static_cast<const int&>(i))> rcci{static_cast<const int&>(i)};
// typeof == const int, decltype == int (!)
pr.doit_c();
return 0;
}
В примере Ref
структура просто используется, чтобы вызвать ошибку компиляции, если T
не соответствует фактическому аргументу конструктора. Problem::doit_c()
метод где decltype(n)
возвращает неконстантный результат, даже если n
const в этом контексте.
Если один переходит от стандарта decltype
к расширению GNU typeof
это, кажется, принимает во внимание постоянство метода.
Теперь мой вопрос: существует ли C ++ 11 / C ++ 14 / C ++ 17 совместимая альтернатива decltype()
/ typeof()
что ведет себя «правильно» (как в: нет ошибки компиляции выше) для выражений, подобных объявлению в const-методе выше?
Отредактировано:
Упрощенное первое предложение, чтобы убрать некоторые ошибки и перестать отвлекать от сути вопроса (спасибо, @skypjack)
Упрощено использование макросов в примере кода (спасибо, @Richard Critten)
decltype
это особенность, которая вроде сидит на двух стульях одновременно. Во-первых, как следует из названия, он может дать вам точный объявленный тип сущности, игнорируя контекст, в котором он используется. Во-вторых, он может рассматривать свой аргумент как выражение, точный тип которого зависит от контекста и его категории значений.
decltype
применение непосредственно к «голому» (не заключенному в скобки) доступу члена класса является особым случаем, в котором decltype
действует в соответствии со своей первой ролью. Не будет лечить n
как выражение. Вместо этого он создаст тип этого члена класса, игнорируя контекст.
Если хочешь это лечить n
как выражение, вы должны заключить его в скобки
struct Problem {
void doit_c() const
{
Ref<decltype(n)> rn1{n}; // `decltype(n)` is `int` -> ERROR
Ref<decltype((n))> rn2{n}; // `decltype((n))` is `const int &` -> compiles OK
}
};
Вы можете узнать эффективный cv-квалифицированный тип n
используя временную ссылку:
void doit_c() const { auto& x = n; Ref<GETTYPE(x)> rn{n}; }
void doit_nc() { auto& x = n; Ref<GETTYPE(x)> rn{n}; }
Но это проще и понятнее заключить в скобки, как показано в Ответ АН.