Hum*_*ler 5 c++ templates clang clang++
clang-11使用-pedantic以下代码段编译时,最新版本的 clang (since ) 会发出警告:
namespace foo {
template <int A>
struct Bar {
~Bar();
};
} // namespace foo
template <int A>
foo::Bar<A>::~Bar(){}
Run Code Online (Sandbox Code Playgroud)
生成的警告(和错误-Werror)是:
<source>:10:12: error: ISO C++ requires the name after '::~' to be found in the same scope as the name before '::~' [-Werror,-Wdtor-name]
foo::Bar<A>::~Bar(){}
~~~~~~~~~~~^~
::Bar
Run Code Online (Sandbox Code Playgroud)
clang是我见过的第一个发出此诊断的编译器,据我所知,上面写的内容是完全有效的 C++。似乎抑制这种情况的两种不同方法是在同一名称空间内定义 或 显式限定析构函数名称——例如:
<source>:10:12: error: ISO C++ requires the name after '::~' to be found in the same scope as the name before '::~' [-Werror,-Wdtor-name]
foo::Bar<A>::~Bar(){}
~~~~~~~~~~~^~
::Bar
Run Code Online (Sandbox Code Playgroud)
Clang 在这里的诊断是否正确?我的理解是类型的名称绝对在正确的名称范围内foo::Bar<A>::~- 并且~Bar<A>()应该没有必要限定。
从发布问题后我了解到的情况来看,严格来说,这个警告是正确的——尽管它很可能是标准措辞中的缺陷。
\n根据 Richard Smith 在LLVM Bug 46979中的说法:
\n\n\n根据书面标准规则,诊断正确;严格来说,C++ 规则要求此析构函数写为
\nRun Code Online (Sandbox Code Playgroud)\ntemplate<typename T>\nA::B<T>::~B<T>()\n根据 C++ [basic.lookup.qual]p6:
\n\n\n在以下形式的限定 ID 中:
\n\n
nested-name-specifier[opt] type-name :: ~ type-name第二个类型名称在与第一个类型名称相同的范围内查找。
\n这意味着在类 A 中查找第二个 B,它只找到类模板 B,而不是注入的类名。
\n这不是一个特别有用的规则,并且可能不是预期的规则,这就是为什么默认情况下禁用此诊断(以及一堆看似合理但形式上不正确的析构函数名称的类似诊断)但包含在 -pedantic 中的原因。
\n
进一步研究这一点,我可以在 C++20 标准中找到[basic.lookup.qual]/6提到的段落,但 C++23 的草案似乎已经改变了这一点——这表明这很可能是一个缺陷。
\n在 C++23 的 [basic.lookup.qual] 草案中,整个部分已经过彻底修改,并且在撰写本文时已被[basic.lookup.qual]/4取代,其中指出:
\n\n\n如果限定名 Q 跟在 ~ 后面:
\n(4.1)如果 Q 是成员限定名称,则它会经历非限定查找和限定查找。
\n(4.2)否则,其嵌套名称说明符 N 应指定一个类型。\n如果 N 有另一个嵌套名称说明符 S,则查找 Q,就好像其查找上下文是由 S 指定的一样。
\n(4.3)否则,如果 N 的终端名称是成员限定名称 M,则查找 Q,就好像 ~Q 出现在 M 的位置一样(如上所述)。
\n(4.4)否则,Q 将进行不合格查找。
\n(4.5) Q 的每次查找仅考虑类型(如果 Q 后面没有跟 <)和专门化为类型的模板。\n如果没有找到任何内容或不明确,则将其丢弃。
\n(4.6)是或包含 Q 的类型名称应在至少执行一次(成功)查找所建立的解释下引用其(原始)查找上下文(忽略 cv 限定)。
\n[示例4:
\nRun Code Online (Sandbox Code Playgroud)\nstruct C {\n typedef int I;\n};\ntypedef int I1, I2;\nextern int* p;\nextern int* q;\nvoid f() {\n p->C::I::~I(); // I is looked up in the scope of C\n q->I1::~I2(); // I2 is found by unqualified lookup\n}\nstruct A {\n ~A();\n};\ntypedef A AB;\nint main() {\n AB* p;\n p->AB::~AB(); // explicitly calls the destructor for A\n}\n\xe2\x80\x94结束示例]
\n
(完整的引文已发布在此处,因为这是草稿,措辞将来可能会发生变化)
\n这似乎通过确保按照预期执行查找来明确纠正此问题。
\n因此,由于措辞上的缺陷,基本上在旧版本的 C++ 下诊断是正确的 - 但 C++23 似乎改变了这一点。我不确定这是否会在旧版本中作为缺陷进行追溯修复,因为似乎没有编译器实际上遵循这种迂腐的要求。
\n| 归档时间: |
|
| 查看次数: |
57 次 |
| 最近记录: |