Ответ 1
Мой первый ответ был неправ, на самом деле, 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-имя или простой идентификатор, поэтому остается только 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>
, компилятор должен предположить, что ваш деструктор
НЕ является шаблоном.
BackTrack.
Далее
6 A template-id that names a class template specialization
is a class-name (clause 9).
Итак, ~foo<int>
называет вашу специализацию шаблона foo<int>
и поэтому является class-name
,
a class-name
- по правилам грамматики a type-name
, а a ~
, за которым следует a 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
.
Стандарт на самом деле является явным в этой теме, d'oh.
И, наконец, 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]