模板化上下文中的显式析构函数

Fre*_*Foo 10 c++ templates destructor

我想vector在模板化的上下文中明确地销毁一个.以下适用于我(GNU C++ 4.3,4.4和Clang ++ 1.1):

template <typename T>
void destroy_vector_owner(VectorOwner<T> *obj)
{
    obj->v.~vector();
    // further cleanup by Python API functions omitted
}
Run Code Online (Sandbox Code Playgroud)

虽然它在Mac OS X v10.5 g++(i686-apple-darwin10-gcc-4.2.1)上失败了

expected class-name before ‘(’ token
Run Code Online (Sandbox Code Playgroud)

如果我改成它

obj->v.~vector<T>();
Run Code Online (Sandbox Code Playgroud)

代码无法用G ++编译,但Clang仍然可以处理它.哪个是正确的成语?在这方面是否已知这些编译器中的任何一个?

更新:定义VectorOwner

template <typename T>
struct VectorOwner {
  PyObject_HEAD
  std::vector<T> v;
};
Run Code Online (Sandbox Code Playgroud)

这是一个必须保持std::vector活着的Python对象.我承认构造稍有危险的,但我需要的压缩存储,摊销O(1)push_back和窃取另一个向量的内容与能力的swap成员.

Seb*_*ach 6

我的第一个答案实际上是错误的,litb 为我指明了正确的方向。正确的答案是\n两种语法都是正确的:

\n
\n

析构函数调用语法。

\n

显式析构函数调用的语法描述于12.4 Destructors

\n
12  In an explicit destructor call, the destructor name appears\n    as a \xcb\x9c followed by a type-name that names the destructor\xe2\x80\x99s \n    class type. The invocation of a destructor is subject to the\n    usual rules for member functions (9.3) [...]\n
Run Code Online (Sandbox Code Playgroud)\n

type-name可以在7.1.5.2 Simple type specifiers

\n
type-name:\n    class-name\n    enum-name\n    typedef-name\n
Run Code Online (Sandbox Code Playgroud)\n

class-name描述于9. Classes

\n
class-name:\n    identifier\n    template-id\n    \n
Run Code Online (Sandbox Code Playgroud)\n

因此,析构函数调用被简化为以下之一

\n
foo.~typedef-name ()\nfoo.~identifier   ()\nfoo.~template-id  ()\n
Run Code Online (Sandbox Code Playgroud)\n

我们这里既没有 typedef-name,也没有简单的标识符,所以只有foo.~template-id()下\n给我们了。

\n
\n

编译器对带有模板参数的析构函数调用的假设。

\n

我们还发现在14. Templates

\n
3 After name lookup (3.4) finds that a name is a template-name,\n  if this name is followed by a <, the < is always taken as the\n  beginning of a template-argument-list and never as a name\n  followed by the less-than operator.\n  \n
Run Code Online (Sandbox Code Playgroud)\n

所以编译器必须在你的例子中假设<模板参数列表的开头。

\n

另外,如果你的析构函数是一个模板(...),那么

\n
4   When the name of a member template specialization appears \n    after . or -> in a postfix-expression, or after nested-name-specifier\n    in a qualified-id, and the postfix-expression or qualified-id explicitly\n    depends on a template-parameter (14.6.2), the member template name must\n    be prefixed by the keyword template. Otherwise the name is assumed to \n    name a non-template.\n
Run Code Online (Sandbox Code Playgroud)\n

所以因为你没有在析构函数调用前f.~foo<int>加上模板,即\nlikef.template ~foo<int>,所以编译器必须假设您的析构函数\n 不是模板。

\n

原路返回。

\n

更远,

\n
6   A template-id that names a class template specialization\n    is a class-name (clause 9).\n
Run Code Online (Sandbox Code Playgroud)\n

因此~foo<int>命名您的模板专业化foo<int>,因此是 a class-name,\naclass-name遵循语法规则 a type-name,并且 a~后跟 atypenameis\na 析构函数调用。所以

\n
foo<int> f;\nf.~foo<int>(); // valid\n
Run Code Online (Sandbox Code Playgroud)\n
\n

没有模板参数的析构函数调用。

\n

但是也

\n
f.~foo(); // valid\n
Run Code Online (Sandbox Code Playgroud)\n

因为3.4.5 Class member access

\n
3 If the unqualified-id is \xcb\x9ctype-name, and the type of the object expression\n  is of a class type C (or of pointer to a class type C), the type-name is\n  looked up in the context of the entire postfix-expression and in the scope of\n  class C. [...]\n  \n
Run Code Online (Sandbox Code Playgroud)\n

因此 f.~foo();,在 中foo,在 内查找f.,并且的范围内foo<int>,仅用 with 引用它是有效的\nfoo

\n
\n

该标准实际上在这个主题上是明确的,哦。

\n

最后,14.3 包含一劳永逸的权限:

\n
5   An explicit destructor call (12.4) for an object that \n    has a type that is a class template specialization may\n    explicitly specify the template-arguments. [Example:\n\n      template<class T> struct A {\n          \xcb\x9cA();\n      };\n      void f(A<int>* p, A<int>* q) {\n          p->A<int>::\xcb\x9cA();      // OK: destructor call\n          q->A<int>::\xcb\x9cA<int>(); // OK: destructor call\n      }\n\n    \xe2\x80\x94end example]\n
Run Code Online (Sandbox Code Playgroud)\n