Вскоре это потому, что ссылка или указатель на тип const не является типом const.
Отметьте, что decltype(*bar)
не const foo
, это const foo &
, и они действительно разные звери.
Рассмотрим пример, приведенный here:
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.
В качестве примечания, приведенный выше пример использует C++, 14-МОГstd::remove_reference_t
и std::remove_pointer_t
черты типа.
Вы можете легко превратить эти строки кода на C++ 11, как это следующим образом:
static_assert(std::is_const<typename std::remove_pointer<decltype(bar)>:: type>::value, "expected const but this is non-const!");
Стоит отметить несколько комментариев к ответу, чтобы дать более подробную информацию:
Спасибо @DanielFischer за вопрос:
Есть краткое объяснение, почему decltype(*bar)
is const foo&
, а не const foo
?
Я не язык-адвокат, но я предполагаю, что это может быть выведено из [expr.unary.op]/1 (курсив мой):
Унарный * оператор выполняет косвенность: выражение, к которому он применяется указатель на тип объекта или указатель на тип функции , а результатом является lvalue, ссылающийся на объект или функцию, на которые указывает выражение.
И [dcl.type.simple]/4.4 (курсив мой):
в противном случае, если е именующий, decltype (е) Т &, где Т представляет собой тип е;
Оба ссылаются на рабочий проект.
Благодаря @LightnessRacesInOrbit для комментария. Обратите внимание, что decltype(*bar)
, являющийся const foo &
, является смешной C++ причудой decltype
, так как *bar
не является const foo &
.
'const foo * bar' создает константу _pointer_, но значение, на которое оно указывает, равно _not_ const. – Aganju
@Aganju нет, это 'foo * const bar;' – greatwolf
'const foo * bar' то же, что и' foo const * bar' Но отличается от 'foo * const bar' –