我想在模板化的上下文中明确销毁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
的定义是
template <typename T>
struct VectorOwner {
PyObject_HEAD
std::vector<T> v;
};
这是一个必须保持std::vector
活着的Python对象。我承认构造稍微有点危险,但我需要紧凑的存储,摊销O(1)push_back
并且能够使用swap
成员窃取另一个向量的内容。
答案 0 :(得分:3)
从n3290,3.4.5类成员访问[basic.lookup.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>
没什么可说的。)
答案 1 :(得分:3)
我的第一个答案实际上是错误的,litb指出了我正确的方向。正确的答案是 这两种语法都是正确的:
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-name,也没有简单的标识符,所以只留下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
范围内的,{/ 1}}范围内的
仅使用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]
来引用它。
最后,14.3包含了一对一的权限:
{{1}}
答案 2 :(得分:0)