I want to explicitly destroy a vector
in a templated context. The following works for me (GNU C++ 4.3, 4.4 and Clang++ 1.1):
template <typename T>
void destroy_vector_owner(VectorOwner<T> *obj)
{
obj->v.~vector();
// further cleanup by Python API functions omitted
}
while it fails on Mac OS X v10.5's g++
(i686-apple-darwin10-gcc-4.2.1
) with
expected class-name before ‘(’ token
If I change it to
obj->v.~vector<T>();
the code fails to compile with G++, but Clang can still handle it. Which is the correct idiom? Are any of these compilers known to be broken in this regard?
Update: the definition of VectorOwner
is
template <typename T>
struct VectorOwner {
PyObject_HEAD
std::vector<T> v;
};
This is a Python object that has to keep an std::vector
alive. I admit that the construct is slightly dangerous, but I need the compact storage, amortized O(1) push_back
and the ability to steal another vector's contents with the swap
member.
From n3290, 3.4.5 Class member access [basic.lookup.classref]
Following that is an example (as a non-normative note) which contains the following snippet of code:
In particular, for
template<typename T, typename Allocator> class vector;
,vector
is the injected-class-name. For that reason, I believeis correct.
(I don't have anything to say about
~vector<T>
at the moment.)You can try following syntax it works in gcc as well:
Demo.
My first answer was wrong actually, litb pointed my into the right direction. The right answer is that both syntaxes are correct:
Destructor call syntax.
The syntax for an explicit destructor call is described in
12.4 Destructors
:type-name
can be found in7.1.5.2 Simple type specifiers
:class-name
is described in9. Classes
:So a destructor call is, simplified, one of the following
We neither have a typedef-name here, nor a simple identifier, so only
foo.~template-id()
is left for us.Compiler's assumption on destructor call with template-arguments.
We also find in
14. Templates
So the compiler must assume in your example that the
<
is the beginning of a template-argument-list.Also, if your destructor would be a template (...), then
So because you did not prefix your destructor call
f.~foo<int>
with template, i.e. likef.template ~foo<int>
, the compiler must assume that your destructor is NOT a template.Backtrack.
Further,
So
~foo<int>
names your template specializationfoo<int>
and therefore is aclass-name
, aclass-name
is by the grammar rules atype-name
, and a~
followed by atypename
is a destructor call. ThereforeDestructor call without template-arguments.
But also
Because
3.4.5 Class member access
:thus in
f.~foo();
,foo
is looked up withinf.
, and within the scope offoo<int>
, it is valid to refer to it just with withfoo
.The standard is actually explicit on this topic, d'oh.
And finally, 14.3 contains the one-and-for-all-permission: