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

C++ 模板化上下文中的显式析构函数,c++,templates,destructor,C++,Templates,Destructor,我想在模板化上下文中显式销毁向量。下面的工作为我(GNU C++ 4.3,4.4和CLAN+++):< /P> 如果我把它改成 obj->v.~vector<T>(); 这是一个Python对象,它必须使std::vector保持活动状态。我承认这个构造有点危险,但我需要紧凑的存储,分期偿还的O(1)push_,以及使用swap成员窃取另一个向量的内容的能力。来自n3290,3.4.5类成员访问[basic.lookup.classref] 3如果非限定id为~type na

我想在模板化上下文中显式销毁
向量。下面的工作为我(GNU C++ 4.3,4.4和CLAN+++):< /P>
如果我把它改成

obj->v.~vector<T>();

这是一个Python对象,它必须使
std::vector
保持活动状态。我承认这个构造有点危险,但我需要紧凑的存储,分期偿还的O(1)
push_
,以及使用
swap
成员窃取另一个向量的内容的能力。

来自n3290,3.4.5类成员访问[basic.lookup.classref]

3如果非限定id为~type name,则在中查找类型名称 整个后缀表达式的上下文。如果 对象表达式是C类类型,类型名称也会被查找 C类范围内的查找。至少一个查找应找到 引用(可能是cv限定的)T.[…]的名称

下面是一个示例(作为非规范性说明),其中包含以下代码片段:

a->~A(); // OK: lookup in *a finds the injected-class-name
特别是对于
模板类向量
vector
是注入的类名。因此,我相信

obj->v.~vector();
这是正确的


(我现在没有什么要说的关于
~vector

您可以尝试以下语法,它在gcc中也适用:

obj->v.template ~vector<T>();
obj->v.template~vector();

.

我的第一个答案是错的实际上,利特把我的答案指向了正确的方向。正确答案是 这两种语法都是正确的:


析构函数调用语法。 显式析构函数调用的语法如
12.4析构函数
所述:

12  In an explicit destructor call, the destructor name appears
    as a ˜ followed by a type-name that names the destructor’s 
    class type. The invocation of a destructor is subject to the
    usual rules for member functions (9.3) [...]
type-name:
    class-name
    enum-name
    typedef-name
类型名称
可在
7.1.5.2简单类型说明符
中找到:

12  In an explicit destructor call, the destructor name appears
    as a ˜ followed by a type-name that names the destructor’s 
    class type. The invocation of a destructor is subject to the
    usual rules for member functions (9.3) [...]
type-name:
    class-name
    enum-name
    typedef-name
类名
9所述。类别

class-name:
    identifier
    template-id
    
因此,析构函数调用被简化为以下之一

foo.~typedef-name ()
foo.~identifier   ()
foo.~template-id  ()
这里既没有typedef名称,也没有简单的标识符,因此只剩下
foo.~template-id()
对我们来说


编译器对带模板参数的析构函数调用的假设。 我们还发现
14。模板

3 After name lookup (3.4) finds that a name is a template-name,
  if this name is followed by a <, the < is always taken as the
  beginning of a template-argument-list and never as a name
  followed by the less-than operator.
  
所以,因为您没有在析构函数调用
f.~foo
前面加上模板,即。 与
f.template~foo
类似,编译器必须假定您的析构函数 不是模板

回溯 此外

6   A template-id that names a class template specialization
    is a class-name (clause 9).
因此,
~foo
命名您的模板专门化
foo
,因此是一个
类名
, 根据语法规则,
类名
是一个
类型名
,后面跟着
类型名的
~
是 析构函数调用。所以

foo<int> f;
f.~foo<int>(); // valid
因为
3.4.5类成员访问

3 If the unqualified-id is ˜type-name, and the type of the object expression
  is of a class type C (or of pointer to a class type C), the type-name is
  looked up in the context of the entire postfix-expression and in the scope of
  class C. [...]
  
因此在
f.~foo()中
foo
f.
中查找,并且在
foo
的范围内,它是有效的 仅使用
foo
引用它


这个标准实际上是明确的,d'oh。 最后,14.3包含了“一对所有”许可:

5   An explicit destructor call (12.4) for an object that 
    has a type that is a class template specialization may
    explicitly specify the template-arguments. [Example:

      template<class T> struct A {
          ˜A();
      };
      void f(A<int>* p, A<int>* q) {
          p->A<int>::˜A();      // OK: destructor call
          q->A<int>::˜A<int>(); // OK: destructor call
      }

    —end example]
5对以下对象的显式析构函数调用(12.4)
5
具有类模板专用化的类型
显式指定模板参数。[示例:
模板结构A{
~A();
};
空f(A*p,A*q){
p->A::~A();//确定:析构函数调用
q->A::«A();//确定:析构函数调用
}
-[结束示例]

你能发布
矢量所有者的定义吗?你到底为什么要这样做?为什么不让对象超出范围?如果出于某种奇怪的原因,这不是一个选项,那么请使用某种智能指针,如
boost::shared_ptr
或其他什么。等等,当它不是指针时,您是如何初始化
obj.v
的?你是否取消引用了一个新表达式的结果?无论如何,我甚至不确定静态分配的对象是否会像这样被删除。。。这不会弄乱你的书堆吗?我明白了,很公平。看起来问题只是因为编译器的错误。(例如,您发布的两个版本都在GCC4.6.1中工作。)这确实是一个非常有趣的问题!你能补充一下“注入的名称”包括名称空间吗?@Kerrek我想这就是类范围的意思。如果这不是你的意思,请在聊天中通知我,如果你不介意的话。该代码说“亲爱的编译器,请查找模板
~vector
”,但OP没有定义模板析构函数。
f.~foo(); // valid
3 If the unqualified-id is ˜type-name, and the type of the object expression
  is of a class type C (or of pointer to a class type C), the type-name is
  looked up in the context of the entire postfix-expression and in the scope of
  class C. [...]
  
5   An explicit destructor call (12.4) for an object that 
    has a type that is a class template specialization may
    explicitly specify the template-arguments. [Example:

      template<class T> struct A {
          ˜A();
      };
      void f(A<int>* p, A<int>* q) {
          p->A<int>::˜A();      // OK: destructor call
          q->A<int>::˜A<int>(); // OK: destructor call
      }

    —end example]