According to cppreference:
If T is a reference type then is_const<T>::value is always false. The proper way to check a potentially-reference type for const-ness is to remove the reference: is_const<typename remove_reference<T>::type>.
That makes sense for references, because there are no const
references, there may only be a reference to a constant. But that should not be the case for pointers as they, unlike references, can be const
. What if I want to check if a template parameter is a const
pointer to a const
type?
template<typename T>
requires std::is_pointer_v<T> // Ok
&& std::is_const_v<std::remove_pointer_t<T>> // Ok
// && std::is_const_v<T> // Fails (2)
void foo(T t) { std::cout << *t << '\n'; }
int main()
{
const int i{5};
const int* const p{&i};
static_assert(std::is_const_v<std::remove_pointer_t<decltype(p)>>); // Ok
static_assert(std::is_const_v<decltype(p)>); // Ok (1)
foo(p);
}
Something is wrong here - constraint (2)
is evaluated to false. But at the same time static_assert()
(1)
is evaluated to true. Why is that? Is it somehow related to template parameter deduction?
First things first, T
is deduced to be const int*
for the call foo(p)
.
Something is wrong here - constraint (2) is evaluated to false. But at the same time static_assert() (1) is evaluated to true. Why is that?
Because std::is_const_v
checks for a top-level const but const int*
has a low-level const(not a top-level const).
On the other hand, decltype(p)
is const int* const
which has a top-level const which is what std::is_const_v
checks.