【问题标题】:Granting friendship to constructor/destructor of template class specialization - works under C++17, but fails under C++20为模板类专业化的构造函数/析构函数授予友谊 - 在 C++17 下工作,但在 C++20 下失败
【发布时间】: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


【解决方案1】:

即使在 C++17 中,Apple clang 12.0.0 也不允许这样做(但显然它在 GCC 10 下编译):

[timr@Tims-Pro:~/src]$ g++ --std=c++17 -c x.cpp
x.cpp:19:42: warning: dependent nested name specifier 'B<T, 0>::' for friend class declaration is not supported; turning off
      access control for 'A' [-Wunsupported-friend]
    template<typename T> friend B<T, 0>::B(T*, int) noexcept;   // C++20 ERROR
                                ~~~~~~~~~^
x.cpp:20:42: error: expected the class name after '~' to name the enclosing class
    template<typename T> friend B<T, 0>::~B() noexcept;   // C++20 ERROR
                                         ^

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2011-01-21
  • 1970-01-01
  • 2022-12-13
  • 2012-12-09
  • 1970-01-01
  • 2016-07-02
  • 2014-05-27
  • 2016-12-04
相关资源
最近更新 更多