Ответ 1
Вскоре это потому, что ссылка или указатель на тип const не является типом const.
Обратите внимание, что decltype(*bar)
не const foo
, это const foo &
, и они действительно разные звери.
Рассмотрим приведенный ниже пример здесь:
std::cout << std::is_const<const int *>::value << '\n'; // false
std::cout << std::is_const<int * const>::value << '\n'; // true
Мы видим, что std::is_const<const int *>::value
ложно и std::is_const<int * const>::value
истинно.
Это потому, что в const int *
тип является указателем на что-то const, это не тип const, как предполагалось is_const
(и стандартом фактически). В int * const
спецификатор const применяется к типу указателя, а не к указанному, поэтому тип является константным, независимо от того, что он указывает.
Что-то подобное применимо для const foo &
, то есть ссылки на что-то const.
Вместо этого вы можете решить эту проблему:
static_assert(std::is_const<std::remove_reference_t<decltype(*bar)>>::value, "expected const but this is non-const!");
Или даже это, для вас не нужно делать *bar
на самом деле:
static_assert(std::is_const<std::remove_pointer_t<decltype(bar)>>::value, "expected const but this is non-const!");
В этом случае, удалив указатель/ссылку с помощью remove_pointer_t
/remove_reference_t
, ваш тип станет const foo
, это фактически тип const.
В качестве дополнительной заметки в приведенном выше примере используются свойства типа С++ 14-ish std::remove_reference_t
и std::remove_pointer_t
.
Вы можете легко превратить эти строки кода в С++ 11, как следует:
static_assert(std::is_const<typename std::remove_pointer<decltype(bar)>:: type>::value, "expected const but this is non-const!");
Стоит упомянуть несколько комментариев к ответу, чтобы дать более подробную информацию:
-
Спасибо @DanielFischer за вопрос:
Есть ли короткое объяснение, почему
decltype(*bar)
естьconst foo&
, а неconst foo
?Я не юрист по языку, но я предполагаю, что это можно сделать из [expr.unary.op]/1 (выделение мой):
Оператор унарного * выполняет косвенное обращение: выражение, к которому оно применяется, должно быть указателем на тип объекта или указателем на тип функции , а результатом является значение lvalue, ссылаясь на объект или функцию, на которые указывает выражение.
И [dcl.type.simple]/4.4 (основное внимание):
в противном случае , если e является lvalue, decltype (e) является T &, где T - тип e;
Оба ссылаются на рабочий проект.
-
Спасибо @LightnessRacesInOrbit за комментарий. Обратите внимание, что
decltype(*bar)
являетсяconst foo &
- смешной С++ quirk изdecltype
, так как*bar
неconst foo &
.