Search code examples
c++c++14language-lawyerc++17decltype

Is decltype of a non-static member function ill-formed?


I'm not sure to perfectly understand [dcl.type]/4.3:

For an expression e, the type denoted by decltype(e) is defined as follows:

  • [...]
  • (4.3) otherwise, if e is an unparenthesized id-expression or an unparenthesized class member access, decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed;
  • [...]

For me, the emphasized part both apply to id-expression and class member access, right?

Playing with my favorite compiler, I get the following.

✓ Accepted by the compiler

namespace N { void f() {} }
using type = decltype(N::f);
type* pf = N::f;

Ok I guess; N::f is an unparenthesized id-expression and does not name a set of overloaded functions.

✗ Rejected by the compiler

namespace N { void f() {} void f(int) {} }
using type = decltype(N::f); // error: decltype cannot resolve address of overloaded function
type* pf = N::f;

Ok; N::f does name a set of overloaded functions.

✗ Rejected by the compiler

struct S { void f(){} };
using type = decltype(S::f); // error: invalid use of non-static member function 'void S::f()'
type* pf = &S::f;

Hum? S::f would name a set of one overloaded function?


All in all, is my understanding of [dcl.type]/4.3 just bad? is gcc trunk wrong? both? none? kamoulox?


Solution

  • The simple reason is that the use of S::f is constrained for class members.

    [expr.prim.id]

    2 An id-expression that denotes a non-static data member or non-static member function of a class can only be used:

    • as part of a class member access in which the object expression refers to the member's class or a class derived from that class, or
    • to form a pointer to member ([expr.unary.op]), or
    • if that id-expression denotes a non-static data member and it appears in an unevaluated operand.

    The last bullet, the one related to your code, only applies to non-static data member. There is no provision for functions.

    I can only speculate as to why it's not allowed, though I previously asked that question.