Явный деструктор в шаблонном контексте

Я хочу явно уничтожить 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
}

в то время как он терпит неудачу на Mac OS X v10.5-е g++ (i686-apple-darwin10-gcc-4.2.1) С

expected class-name before ‘(’ token

если я изменю его на

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

код не компилируется с G++, но Clang все еще может его обрабатывать. Какая идиома правильная? Любой из этих компиляторов поломанной в этом уважение?

обновление определение VectorOwner is

template <typename T>
struct VectorOwner {
  PyObject_HEAD
  std::vector<T> v;
};

это объект Python, который должен содержать std::vector жив. Я признаю, что конструкция немного опасна, но мне нужно компактное хранилище, амортизированное O(1) push_back и возможность украсть содержимое другого вектора с помощью swap член.

3 ответов


мой первый ответ был неправильным на самом деле, литб указал мне в правильном направлении. Правильный ответ что оба синтаксиса верны:


синтаксис вызова деструктора.

синтаксис явного вызова деструктора описан в 12.4 Destructors:

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 можно найти в 7.1.5.2 Simple type specifiers:

type-name:
    class-name
    enum-name
    typedef-name

class-name описанное в 9. Classes:

class-name:
    identifier
    template-id

таким образом, вызов деструктора, упрощенный, один из после

foo.~typedef-name ()
foo.~identifier   ()
foo.~template-id  ()

у нас здесь нет ни имени typedef, ни простого идентификатора, поэтому только foo.~template-id() осталось для нас.


предположение компилятора о вызове деструктора с аргументами шаблона.

мы также находим в 14. Templates

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.

поэтому компилятор должен предположить, в вашем примере, что < начало шаблона-аргумента-списка.

кроме того, если ваш деструктор будет шаблон (...), тогда

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

Итак, потому что вы не префикс вызова деструктора f.~foo<int> с шаблоном, т. е. как f.template ~foo<int> компилятор должен предположить, что ваш деструктор это не шаблон.

запудрены.

далее

6   A template-id that names a class template specialization
    is a class-name (clause 9).

так ~foo<int> имена вашей специализации шаблона foo<int> и поэтому class-name, а class-name по правилам грамматики a type-name и ~ затем typename это вызов деструктора. Поэтому

foo<int> f;
f.~foo<int>(); // valid

вызов деструктора без аргументов шаблона.

, но и

f.~foo(); // valid

, потому что 3.4.5 Class member access:

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<int>, это действительно ссылаться на него просто с помощью foo.


стандарт на самом деле явного на эту тему, черт.

и, наконец, 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]

из n3290, 3.4.5 доступ к члену класса [basic.уважать.classref]

3 Если unqualified-id ~type-name, то type-name ищется в контекст всего постфиксного выражения. Если тип T выражение объекта имеет тип класса C, также просматривается имя типа в рамках класса C. По крайней мере один из поисков должен найти имя, которое относится к (возможно, CV-qualified) T. [...]

Ниже приведен пример (как ненормативная заметка), которая содержит следующий фрагмент кода:

a->~A(); // OK: lookup in *a finds the injected-class-name

в частности, для template<typename T, typename Allocator> class vector;, vector - Это вводят-класс-имя. По этой причине я верю

obj->v.~vector();

является правильным.

(мне нечего сказать о ~vector<T> на данный момент.)


вы можете попробовать следующий синтаксис, он также работает в gcc:

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

демо.