Явный деструктор в шаблонном контексте
Я хочу явно уничтожить 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>();
демо.