模板内的模板友元函数 class

A template friend function inside a template class

template class 中实现 template friend function 的问题在过去已经讨论过,似乎 不同编译器的行为不同。

检查 gccclang 的最新可用版本似乎已做出决定,要求实施 template friend function 之外 template class.

以下代码被 gccclang 的最新版本拒绝(gcc x86-64 9.2.0 和 clang x86- 64 9.0.0) 使用 -std=c++2a 编译时。 clang 的过去版本都可以(例如 clang x86-64 7.0.0)。

template<long Num>
struct A {
    template<long Num1, long Num2>
    friend int foo(A<Num1> a1, A<Num2> a2) {
        return 1;
    }
    // the compilation error occurs only with a template friend function
    // and only if *implemented inside* a template class
};

int main() {
    A<1> a1;
    A<2> a2; // commenting this line removes the error
}

两个编译器都抱怨 foo 的重新定义:

<source>:4:16: error: redefinition of 'foo'    
    friend int foo(A<Num1> a1, A<Num2> a2) {    
               ^    
<source>:11:10: note: in instantiation of template class 'A<2>' requested here    
    A<2> a2;    
         ^

关于这个问题是否有新的官方解决方案或者它只是最新的编译器时尚?

https://godbolt.org/z/ySrVe3

我从CWG 2174的决议中找出了相关的措辞。在C++17中的[temp.inst]/2中:

However, for the purpose of determining whether an instantiated redeclaration is valid according to [basic.def.odr] and [class.mem], a declaration that corresponds to a definition in the template is considered to be a definition.

因此,编译器需要将定义的实际实例化推迟到需要 foo 的定义存在的位置(在您的代码中,没有这样的位置,所以 foo 未实例化),但即使定义未实例化,编译器仍然需要诊断同一翻译单元内的多个定义 就好像 定义每次都已实例化声明被实例化。

在我看来,这条规则使得使用友元函数变得不必要地困难而没有明显的好处,如果在 class 模板中定义一个友元函数的多个定义会更好,在其中实例化相同的 TU,被视为单一定义。也许,如果我手上有更多时间,我会建议对标准进行这样的更改。 (是的,我是说我没有时间,所以如果有人想这样做,请继续,不要担心重复工作。)

除非做这样的改动,貌似做,其实需要在class模板外定义友元函数