This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115b. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-08-20
[Voted into WP at April, 2006 meeting.]
Lets start with the proposed solution. In 12.4.6 [over.ref], replace line ...
postfix-expression -> id-expression.... with the lines ...
postfix-expression -> templateopt id-expression(This then is a copy of the two lines in 7.6.1 [expr.post] covering "->dtor")
postfix-expression -> pseudo-destructor-name
Alternatively remove the sentence "It implements class member access using ->" and the syntax line following.
Reasons:
Currently stdc++ is inconsistent when handling expressions of the form "postfixexpression->scalar_type_dtor()": If "postfixexpression" is a pointer to the scalar type, it is OK, but if "postfixexpression" refers to any smart pointer class (e.g. iterator or allocator::pointer) with class specific CLASS::operator->() returning pointer to the scalar type, then it is ill-formed; so while c++98 does allow CLASS::operator->() returning pointer to scalar type, c++98 prohibits any '->'-expression involving this overloaded operator function.
Not only is this behaviour inconsistent, but also when comparing the corresponding chapters of c++pl2 and stdc++98 it looks like an oversight and unintended result. Mapping between stdc++98 and c++pl2:
c++pl2.r.5.2 -> 5.2 [expr.post]For the single line of c++pl2.r.5.2 covering "->dtor", 5.2 [expr.post] has two lines. Analogously c++pl2.r.5.2.4 has been doubled to 5.2.4 [expr.pseudo] and 5.2.5 [expr.ref]. From 13.5.6 [over.ref], the sentence forbiding CLASS::operator->() returning pointer to scalar type has been removed. Only the single line of c++pl2.r.13.4.6 (<-> c++pl2.r.5.2's single line) has not gotten its 2nd line when converted into 13.5.6 [over.ref].
c++pl2.r.5.2.4 -> 5.2.4 [expr.pseudo] + 5.2.5 [expr.ref]
c++pl2.r.13.4 -> 13.3.1.2 [over.match.oper]
c++pl2.r.13.4.6 -> 13.5.6 [over.ref]
Additionally GCC32 does is right (but against 13.5.6 [over.ref]).
AFAICS this would not break old code except compilers like VC7x and Comeau4301.
It does not add new functionality, cause any expression class_type->scalar_type_dtor() even today can be substituted through (*class_type).scalar_type_dtor().
Without this fix, template functions like some_allocator<T>::destroy(p) must use "(*p).~T()" or "(*p).T::~T()" when calling the destructor, otherwise the simpler versions "p->~T()" or "p->T::~T()" could be used.
Sample code, compiled with GCC32, VC7[1] and Comeau4301:
struct A {};//any class template <class T> struct PTR { T& operator* () const; T* operator-> () const; }; template <class T> void f () { { T* p ; p = new T ; (*p).T::~T() ;//OK p = new T ; (*p).~T() ;//OK p = new T ; p->T::~T() ;//OK p = new T ; p->~T() ;//OK } { PTR<T> p = PTR<T>() ; (*p).T::~T() ;//OK (*p).~T() ;//OK p.operator->() ;//OK !!! p->T::~T() ;//GCC32: OK; VC7x,Com4301: OK for A; ERROR w/ int p->~T() ;//GCC32: OK; VC7x,Com4301: OK for A; ERROR w/ int } } void test () { f <A> (); f <int>(); }
Proposed resolution (April, 2005):
Change 12.4.6 [over.ref] paragraph 1 as indicated:
operator-> shall be a non-static member function taking no parameters. It implements the class member access
usingsyntax that uses ->postfix-expression -> templateopt id-expression
postfix-expression -> pseudo-destructor-nameAn expression x->m is interpreted as (x.operator->())->m for a class object x of type T if T::operator->() exists and if the operator is selected as the best match function by the overload resolution mechanism (12.2 [over.match]).