c++ - 如何显式调用命名空间限定的析构函数?

标签 c++ g++ standards clang++

我很惊讶以下简单代码无法编译(使用 gcc,版本 4.8.1)

#include <string>
void test()
{
  std::string* p = new std::string("Destruct me");
  p->std::~string();
}

它说:错误:“~”之前的范围“std”不是类名。然而阅读标准,我会说语法应该是“postfix-expresssion -> pseudo-constructor-name”,其中 pseudo-constructor-name 可以是“nested-name-specifier ~ type-name”的形式,nested-name-specifier 可以是"标识符::"。

省略“std::”会导致提示在左括号之前需要一个类名,并将其放在波浪号之后会提示在“::”之前需要一个类名。经过一番尝试,我发现它会在编写 p->std::string::~string(); 时编译(但不是在编写 p->std::string::时) ~std::string(); 代替)。但是用自己的类型名限定析构函数并不是一个中立的操作;我从标准 12.4:13 中的示例(但奇怪的是不是来自规范文本)收集到,这会强制调用确切的静态(基)类的析构函数,而不是作为(派生最多的)类的虚函数type of) 指向的实际对象。在这里它没有区别,但在类似的情况下它会;为什么语法会强制使用静态类型?

但是,使用 clang 而不是 gcc,即使提到的变体也会产生语法错误。但是,如果您在阅读错误消息时喜欢这种幽默,那么 clang 的错误消息会更有趣:for p->std::string::~string();它给出了“期望在 '~' 之后的类名来命名析构函数”(确实如此;有人想知道如果以波浪号为前缀,哪种类名不会命名析构函数),并且对于我的初始试用 p ->std::~string() 它反驳“合格的成员访问是指命名空间'std'中的一个成员”(再次想知道这有什么问题;实际上要调用的析构函数存在于命名空间中'标准')。我已经尝试了所有 8 种合理的组合(std::和/或 string::在波浪号之前,和/或 std::在它之后)并且它们都没有用 clang 编译。

我可以使用 using std::string; 让它编译,即使是 clang。但我觉得奇怪的是,我在标准中找不到任何迹象表明这种声明在这种情况下是必要的。事实上,我根本找不到任何解决调用命名空间限定类的析构函数的问题.我错过了什么明显的东西吗?

作为最后一点,我想补充一点,在调用析构函数时必须使用命名空间限定符,这让我感到很奇怪。由于这是来自指定对象(此处为 *p)的成员访问,不应该依赖于参数的查找使明确限定命名空间变得不必要?

最佳答案

在标准中,在:

§3.4.5/3

If the unqualified-id is ~type-name, the type-name is looked up in the context of the entire postfix-expression.

因此看来 ~string应在 std:: 的上下文中查找命名空间。

事实上,考虑到相应的自制版本在 GCC 和 Clang 上的工作方式如下:

namespace STD {
class STRING {};
}

int main() {
    STD::STRING* a = new STD::STRING();
    a->~STRING();
}

Live demo with clang++ Live demo with g++

我会继续说这很可能是一个错误。


显然,鉴于 std::string真的是std::basic_string<char>如果你打电话:

a->~basic_string();

Live demo with clang++ Live demo with g++

然后一切编译正常。

我仍然认为这是一个错误,考虑到以下示例(取自标准)显示 typedef s 也应该工作:

struct B {
    virtual ~B() { }
};

struct D : B {
    ~D() { } 
};

D D_object;

typedef B B_alias;

B* B_ptr = &D_object;

void f() {
D_object.B::~B();
    B_ptr->~B();
    B_ptr->~B_alias();
    B_ptr->B_alias::~B();
    B_ptr->B_alias::~B_alias();
}

这个概念连同 §3.4.5/3 应该保证:

p->~string();

应该可以。

关于c++ - 如何显式调用命名空间限定的析构函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24593942/

相关文章:

c++ - 如何构建 64 位版本的 Crypto++ dll?

C++:读取文件时程序卡住。为什么?

c++ - Mex 找不到 g++

c++ - 将 QUrl 传递给 QNetworkRequest 构造函数会导致 "non-class type"编译器错误

html - 有效的字体系列名称

c++ - "int f(int(fn)())"和 "int f(int(*fn)())"之间的区别?

c++ - 将可调用对象传递给成员函数

c++ - 使用位掩码生成排列

linux - 为什么我没有从 g++ 中收到 "Multiple definition"错误?

javascript - body 内的脚本标签和 appendChild 的行为