模板类中的模板朋友功能

时间:2019-12-19 19:42:18

标签: c++ templates language-lawyer friend

过去已经讨论了在template friend function内实现template class的问题,并且似乎an unresolved issue in the standard的问题与不同编译器的行为不同。

检查 gcc clang 的最新可用版本,似乎已做出决定,要求将template friend function的实现 template class的>外部

以下代码被 gcc clang 的最新版本(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

1 个答案:

答案 0 :(得分:0)

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

  

但是,为了根据[basic.def.odr]和[class.mem]确定实例化的重新声明是否有效,将与模板中的定义相对应的声明视为定义。< / p>

因此,要求编译器将定义的实际实例推迟到需要存在foo定义的点为止(在您的代码中没有这样的点,因此foo (未实例化),但是即使未实例化定义,编译器仍需要在同一翻译单元中诊断多个定义,就好像每次实例化声明时都已实例化一样。< / p>

在我看来,该规则使不必要地使用友善函数变得毫无益处,而如果考虑在同一个TU中实例化的类模板中定义的友善函数的多个定义会更好作为一个单一的定义。也许,如果我有更多时间可用,我建议对标准进行这样的更改。 (是的,我是说我没有时间,所以如果其他人想要这样做,请继续进行,而不必担心重复的工作。)

除非进行了这样的更改,否则实际上您似乎确实需要在类模板之外定义friend函数。