YSC
YSC

Reputation: 40060

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?

Upvotes: 9

Views: 1627

Answers (2)

Will Wray
Will Wray

Reputation: 107

It's worth a note that decltype(&S::f) works here as pointer-to-member-function type,
again unless the f names a set of overloaded (member) functions.

The function type itself can be extracted from the pointer-to-member-function type.
If the member function is cv-or-ref qualified then it has an abominable function type.
The std traits are lacking here - a library like Boost.CallableTraits helps.

Upvotes: 1

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.

Upvotes: 10

Related Questions