使用 GCC 编译模板友谊错误,但不使用 clang

Template friendship error compilation with GCC but not with clang

此代码使用 clang 3.7.1(没有诊断)编译,但因 GCC[=23 而失败=] 5.3.0 (live example):

#include <iostream>

template<typename T>
struct A {
    void foo()
    {
        static_cast<T*>(this)->implementation();
    }
};

struct Crtp : A<Crtp> {
    template<typename T>
    friend struct A;
private:
    void implementation() { std::cout << "implementation()\n"; }
};

int main()
{
    Crtp c;
    c.foo();
}

GCC 的错误信息如下:

main.cpp:13:16: error: specialization of 'A' after instantiation friend struct A;

哪一个是正确的,为什么?是 GCC / clang 的错误吗?

我认为这是 gcc 的错误。

A template friend class 声明只是声明,不是定义。 允许重新声明 class 模板,除非它具有不同的 class-key(参见 N4527 14.5.1.4)。

特化或实例化可以发生两次或更多次。 显式专业化只能发生一次(N4527 14.7.3.6)。

然后,gcc 的诊断很奇怪,因为没有明确的专门化。

似乎是一个旧的 g++ 错误 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52625)。

已举报,未更正,如果我理解正确,

我们确实有一些模板名称解析几率:

struct Crtp : A<Crtp> {
  A x; // A refers to A<Crtp>
};

现在事情清楚了:

template<typename T> friend struct A; 

指的是:

template<typename T> friend struct A<Crtp>; 

这是...是的,部分专业化(真的很棘手)。

所以这里 GCC 是正确的。

你真正需要的是:

struct Crtp : A<Crtp> {
friend struct A;
private:
    void implementation() { std::cout << "implementation()\n"; }
};