Результат decltype в методах const

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)

2

Решение

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

Другие решения

Вы можете узнать эффективный 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}; }

Но это проще и понятнее заключить в скобки, как показано в Ответ АН.

1

По вопросам рекламы [email protected]