Явный деструктор в шаблонном контексте - PullRequest
10 голосов
/ 27 июля 2011

Я хочу явно уничтожить 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 версии 10.5 g++ (i686-apple-darwin10-gcc-4.2.1) с

expected class-name before ‘(’ token

Если я поменяю его на

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

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

Обновление : определение VectorOwner равно

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

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

Ответы [ 3 ]

3 голосов
/ 28 июля 2011

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


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

Синтаксис явного вызова деструктора описан в 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 - по грамматическим правилам 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]
3 голосов
/ 27 июля 2011

Начиная с n3290, 3.4.5 Доступ к членам класса [basic.lookup.classref]

3 Если неквалифицированным идентификатором является ~ имя-типа, имя типа ищется в контекстевсего постфиксного выражения.Если тип T выражения объекта относится к типу класса C, имя типа также ищется в области видимости класса C. По крайней мере, один из поисков должен найти имя, которое относится к (возможно, cv-квалифицированному) 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> . )

0 голосов
/ 27 июля 2011

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

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

Демо .

...