bar(type (&)[x]) definition does not match bar(type (&)[x]) declaration?

Viewed 105

This is a follow up of Template class type alias failing substitution in member declaration

Consider this code:

// A
template <typename T>
struct foo {
    using type = unsigned;
   
    template <type x>
    void bar(type (&)[x]);
};
    
template <typename T>
template <typename foo<T>::type x>
void foo<T>::bar(type (&)[x]){}

gcc emits the following error:

<source>:13:6: error: no declaration matches 'void foo<T>::bar(foo<T>::type (&)[x])'
   13 | void foo<T>::bar(type (&)[x]){}
      |      ^~~~~~
<source>:8:10: note: candidate is: 'template<class T> template<unsigned int x> void foo<T>::bar(foo<T>::type (&)[x])'
    8 |     void bar(type (&)[x]);
      |          ^~~
<source>:4:8: note: 'struct foo<T>' defined here
    4 | struct foo {
      |        ^~~
Compiler returned: 1

clang:

<source>:13:14: error: out-of-line definition of 'bar' does not match any declaration in 'foo<T>'
void foo<T>::bar(type (&)[x]){}
             ^~~
1 error generated.
Compiler returned: 1

When I remove what is identical in the erroneous definition and the candidate I get this:

// B
template <typename T>
struct foo {
    using type = unsigned;

    template <type x>
    void bar();
};

template <typename T>
template <typename foo<T>::type x>
void foo<T>::bar(){}

This compiles fine (gcc / clang)

An attempt to answer the original question (by Darhuuk, slightly modified) was this:

// C
#include <type_traits>

template <typename T> struct length { using type = unsigned int; };    
template <typename T> using length_t = typename length<T>::type;

template <typename type>
class Object {
  template <length_t<Object<type>> length>
  void put(type (&)[length]);
};

template <typename type>
template <length_t<Object<type>> length>
void Object<type>::put(type (&)[length]) {}

int main() {}

Clang seems to have similar problems as with the original code and emits the error:

<source>:15:20: error: out-of-line definition of 'put' does not match any declaration in 'Object<type>'
void Object<type>::put(type (&)[length]) {}
                   ^~~
1 error generated.

while gcc compiles it without complaints.

Who is right about C? Is it a bug in clang or is gcc being lax?

Why does A not compile while B does?

1 Answers
Related