Почему переменные-члены объекта const не являются константами

Просто задал подобный вопрос, который сводится к этому.

#include <iostream>
using namespace std;

struct A {
    A() : a{1} {};
    int a;
};

template <typename Which>
struct WhichType;

int main() {
    const A a;
    const A& a_ref = a;
    const A* a_ptr = &a;
    WhichType<decltype(a.a)> which_obj; // template evaluates to int
    WhichType<decltype(a_ref.a)> which_ref; // template evaluates to int
    WhichType<decltype(a_ptr->a)> which_ptr; // template evaluates to int

    return 0;
}

Почему шаблоны не становятся const int вместо int?

Ответ 1

decltype дает вам "объявленный тип" операнда, если он не заключен в дополнительный набор круглых скобок.

Чтобы получить фактический тип выражения, то есть const int, вам нужно написать decltype((a.a)) и т.д.

decltype всегда возвращает ссылочный тип для выражений lvalue, отличных от имен.

Ответ 2

Когда передано имя идентификатора (или члена), он возвращает тип объявления.

Когда передано другое выражение, оно возвращает что-то более близкое к тому, что вы хотите, но ссылочное.

WhichType<std::remove_reference_t<decltype((a_ptr->a))>> which_ptr; // template evaluates to const int!

живой пример или если вы хотите l/r ценность:

WhichType<decltype((a_ptr->a))> which_ptr2; // template evaluates to const int&
WhichType<decltype(((const A){}.a))> which_ptr3; // template evaluates to const int

вы можете добавить &&, чтобы сделать его "реальной" ссылкой rvalue здесь.

WhichType<decltype(((A){}.a))&&> which_ptr4; // template evaluates to int&&!

живой пример.