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

Reply via email to