【发布时间】:2021-06-15 11:16:52
【问题描述】:
我发现了一种情况,代码在C++17下编译成功,但在C++20下编译失败。
这会阻止我们将现有的代码设计升级到更新的标准。
为什么这不能在 C++20 下编译?这似乎是对向后兼容性的奇怪破坏。
当我尝试将友谊授予模板类专业化的构造函数/析构函数时会发生错误。
我正在使用带有 Ninja 的 MSVC 进行编译。
C++17下编译成功。
在 C++20 下,我收到以下错误:
error C2838: '{ctor}': illegal qualified name in member declaration
error C2838: '{dtor}': illegal qualified name in member declaration
这里是在C++20下导致错误的代码的简化复现,但在C++17下编译成功:
template<typename T, int V> class B {};
// specialization of class B
template<typename T> class B<T, 0> {
private:
T _t; // private data member
public:
constexpr inline B(T* p, int i) noexcept; // B constructor declaration
virtual inline ~B() noexcept; // B destructor declaration
};
// empty class with only private static data, no methods
class A {
private:
static int x; // private static variable
public:
// ERRORS HERE IN C++20, but compiles successfully in C++17
template<typename T> friend B<T, 0>::B(T*, int) noexcept; // C++20 ERROR
template<typename T> friend B<T, 0>::~B() noexcept; // C++20 ERROR
};
int A::x = 0; // global definition of private static variable
template<typename T> // B constructor definition
constexpr inline B<T, 0>::B(T* p, int i) noexcept : _t(0) { A::x++; }
template<typename T> // B destructor definition
inline B<T, 0>::~B() noexcept { A::x++; }
int main() {
A a;
B<const int, 0> b(0, 0);
}
我知道我可以通过为 B(包括 ALL 专业化)的整个班级模板授予友谊来解决此问题,但这是不可取的,因为我们想限制尽可能减少友谊。
只有一两个模板专精(几十个)实际上需要这种友谊,如果没有必要,我们不希望将友谊授予其他模板专精。
【问题讨论】:
-
来自cppreference:朋友声明不能引用部分特化,但可以引用完整特化:
-
@super 我相信这是指朋友类,而不是朋友功能,所以我不确定它是否适用于这里?
-
不正确。这段话以开始
-
@Giffyguy temp.friend/7 中的措辞相当明确地指出“朋友声明不应声明部分特化”(尽管提供的唯一示例指的是类,而不是函数) .我建议您在问题中添加
language-lawyer标签。 -
当查看类似的(但已删除)question 时,我发现这将与任何成员函数除了构造函数或析构函数一起编译。编译器可能正在寻找类型名称,并因构造函数/析构函数(没有返回类型)的存在而感到困惑。
标签: c++ language-lawyer c++20 friend friend-function