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).