Luk*_*rth 7 c++ llvm clang language-lawyer c++20
C++20 标准在 [vector.overview]/4 中声明:
如果分配器满足分配器完整性要求,则在实例化向量时可以使用不完整类型 T。T 应在引用所得向量专业化的任何成员之前完成。
默认分配器std::allocate确实满足allocator completeness requirements. 主要问题是“引用”在这种情况下意味着什么。我感到困惑的代码是以下代码的变体:
#include <vector>
class MyClass;
class MyContainer
{
std::vector<MyClass> member;
};
class MyClass {};
int main()
{}
Run Code Online (Sandbox Code Playgroud)
上面的代码可以在各种编译器中正常编译。如果我明确默认默认构造函数,它仍然可以编译:
#include <vector>
class MyClass;
class MyContainer
{
MyContainer() = default;
std::vector<MyClass> member;
};
class MyClass {};
int main()
{}
Run Code Online (Sandbox Code Playgroud)
然而,当我将默认构造函数定义为“空”时,会发生一些奇怪的事情。这是代码(位于编译器资源管理器):
#include <vector>
class MyClass;
class MyContainer
{
MyContainer() {};
std::vector<MyClass> member;
};
class MyClass {};
int main()
{}
Run Code Online (Sandbox Code Playgroud)
有了这个代码:
In file included from <source>:1:
In file included from /opt/compiler-explorer/gcc-12.2.0/lib/gcc/x86_64-linux-gnu/12.2.0/../../../../include/c++/12.2.0/vector:64:
/opt/compiler-explorer/gcc-12.2.0/lib/gcc/x86_64-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_vector.h:367:35: error: arithmetic on a pointer to an incomplete type 'MyClass'
_M_impl._M_end_of_storage - _M_impl._M_start);
~~~~~~~~~~~~~~~~~~~~~~~~~ ^
/opt/compiler-explorer/gcc-12.2.0/lib/gcc/x86_64-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_vector.h:526:7: note: in instantiation of member function 'std::_Vector_base<MyClass, std::allocator<MyClass>>::~_Vector_base' requested here
vector() = default;
^
<source>:7:5: note: in defaulted default constructor for 'std::vector<MyClass>' first required here
MyContainer() {};
^
<source>:3:7: note: forward declaration of 'MyClass'
class MyClass;
Run Code Online (Sandbox Code Playgroud)
我的第一直觉,只查看 Clang 15 错误,是“clang 是正确的”。默认构造函数确实(隐式)调用 的默认构造函数std::vector<MyClass>,并且标准规定,只要MyClass不完整,就不能引用成员。
然而,我非常确定这不是答案,因为:
所以,我的问题是:这是 Clang 15 的错误吗?如果是这样,是否(隐式)调用std::vector<MyClass>不被视为“引用”的默认构造函数 [vector.overview]/4?
我确实在LLVM 错误跟踪器中搜索了术语“向量”和“不完整”,但没有找到任何结果,所以如果这是一个已知的错误,我猜它在 的上下文中是未知的std::vector。
这是作为两个问题的重复而结束的,在我看来,这是不正确的。差异虽然微妙但相关。这两个问题是:
std::vector<incompleteType>这里,显式引用了的成员(即::reverse_iterator)。这显然没有被[vector.overview]/4涵盖。但是,我在问题中并没有这样做。确实,这里的“引用”并不清楚。我认为这句话的意思可能是,T在你做任何需要最终专业化的任何成员的定义存在的事情之前,它应该是完整的。
在第二个例子中
class MyClass;
class MyContainer
{
MyContainer() = default;
std::vector<MyClass> member;
};
class MyClass {};
Run Code Online (Sandbox Code Playgroud)
std::vector<MyClass>在编译器实际隐式定义封闭类 的默认构造函数之前,不需要 的默认构造函数的定义MyContainer。根据[dcl.fct.def.default]/5的最后一句,直到第一次的MyContainer默认构造函数被 odr 使用或需要进行持续评估时,这种情况才会发生:
未定义为已删除的非用户提供的默认函数(即在类中隐式声明或显式默认)在使用 odr ([basic.def.odr]) 或需要常量求值 ([表达式.const])。
您的第一个示例(您没有声明任何默认构造函数)和第二个示例(您在类定义中将其声明为默认构造函数)的处理方式类似:在这两种情况下,构造函数都不是用户提供的,因此它不会急切地定义。在这两个示例中,MyContainer都有一个非用户提供的复制构造函数、移动构造函数、复制赋值运算符、移动赋值运算符和析构函数,它们同样在需要定义之前才定义,因此程序避免“引用”任何成员的std::vector<MyClass>。
在第三个示例中,由于构造函数是用户提供的,因此即使从未使用过它,它也会被定义,并且其定义隐式调用 的默认构造函数std::vector<MyClass>,即后者被“引用”。
当您违反规则时(如在第三个示例中所做的那样),程序将出现未定义的行为。我知道您尝试过的大多数编译器甚至都没有警告您,这似乎非常不友好,但是当您滥用不完整类型时不需要进行诊断是有原因的:模板很难以不导致错误的方式检查完整性。更大的问题(尽管我相信 Clang 正在针对这个问题开展工作)。
| 归档时间: |
|
| 查看次数: |
402 次 |
| 最近记录: |