This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 117a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2025-04-13


1836. Use of class type being defined in trailing-return-type

Section: _N4567_.5.1.1  [expr.prim.general]     Status: CD5     Submitter: Mike Miller     Date: 2014-01-17

[Voted into the WP at the July, 2017 meeting.]

According to _N4567_.5.1.1 [expr.prim.general] paragraph 3,

Unlike the object expression in other contexts, *this is not required to be of complete type for purposes of class member access (7.6.1.5 [expr.ref]) outside the member function body.

Is this special treatment of member access expressions intended to apply only to *this, or does it apply to other ways of specifying the class being defined in the object expression? For example,

 struct S { int i; auto f1() -> decltype((*this).i); // okay auto f2(S& This) -> decltype(This.i); // okay? auto f3() -> decltype(((S*)0)->i); // okay? }; 

There is implementation divergence on this question.

If the intent is to allow object expressions other than *this to have the current class type, this specification should be moved from _N4567_.5.1.1 [expr.prim.general] to 7.6.1.5 [expr.ref] paragraph 2, which is where the general requirement for complete object expression types is found.

On a related point, the note immediately following the above-cited passage is not quite correct:

[Note: only class members declared prior to the declaration are visible. —end note]

This does not apply when the member is a “member of an unknown specialization,” per 13.8.3.2 [temp.dep.type] bullet 5.3 sub-bullet 1; for example,

 template<typename T> struct S : T { auto f() -> decltype(this->x); }; 

Here x is presumed to be a member of the dependent base T and is not “declared prior to the declaration” that refers to it.

Proposed resolution (May, 2017):

  1. Change 7.5.3 [expr.prim.this] paragraph 2 as follows:

  2. Unlike the object expression in other contexts, *this is not required to be of complete type for purposes of class member access (7.6.1.5 [expr.ref]) outside the member function body. [Note: Only class members declared prior to the declaration are visible. —end note] [Note: In a trailing-return-type, the class being defined is not required to be complete for purposes of class member access (7.6.1.5 [expr.ref]). Class members declared later are not visible. [Example:

     struct A { char g(); template<class T> auto f(T t) -> decltype(t + g()) { return t + g(); } }; template auto A::f(int t) -> decltype(t + g()); 

    end example] end note]

  3. Change 7.6.1.5 [expr.ref] paragraph 2 as follows, splitting the paragraph into two paragraphs as indicated:

  4. For the first option (dot) the first expression shall be a glvalue having complete class type. For the second option (arrow) the first expression shall be a prvalue having pointer to complete class type. In both cases, the class type shall be complete unless the class member access appears in the definition of that class. [Note: If the class is incomplete, lookup in the complete class type is required to refer to the same declaration (6.4.7 [basic.scope.class]). —end note]

    The expression E1->E2 is converted to the equivalent form (*(E1)).E2; the remainder...



close