https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98820
Bug ID: 98820
Summary: Placeholder (auto) non-type template parameter wrongly
deduced to 'const' for class type arguments
Product: gcc
Version: 11.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: davveston at gmail dot com
Target Milestone: ---
As per [temp.param]/6 in N4861, for non-template parameters (including a type
that contains a placeholder type):
"[...] The top-level cv-qualifiers on the template-parameter are ignored when
determining its type."
and as per [dcl.type.decltype]/1.2:
"For an expression E, the type denoted by decltype(E) is defined as follows:
- [...] naming a non-type template-parameter, decltype(E) is the type of the
template-parameter after performing any necessary type deduction [...]"
Thus, the following example should arguably be well-formed:
#include <type_traits>
struct A{};
template <auto a>
void f() {
static_assert(std::is_same_v<decltype(a), A>);
}
template <auto const a>
void g() {
static_assert(std::is_same_v<decltype(a), A>);
}
int main() {
constexpr A a{};
f<a>();
g<a>();
}
However GCC rejects it as `decltype(a)` resolves to `A const` rather than `A`.
---
We may note that:
1) Clang accepts the program, and
2) Both Clang and GCC accepts the program when using a structural type directly
instead of a placeholder type for the non-type template parameter; replacing
the definitions of `f` and `g` above with:
template <A a>
void f() {
static_assert(std::is_same_v<decltype(a), A>);
}
template <A const a>
void g() {
static_assert(std::is_same_v<decltype(a), A>);
}
3) Both clang and GCC accepts the program when using a placeholder type but
with a non-class type as template argument to it; replacing the definitions of
`f` and `g` above with:
template <auto a>
void f() {
static_assert(std::is_same_v<decltype(a), int>);
}
template <auto const a>
void g() {
static_assert(std::is_same_v<decltype(a), int>);
}
and calling them as f<0>() and g<0>();
---
These standard rules are arguably somewhat confusing given that the template
parameter object itself (associated with the class-type non-type template
parameter) is `const` ([temp.param]/8).