Reputation: 40060
I'm not sure to perfectly understand [dcl.type]/4.3
:
For an expression
e
, the type denoted bydecltype(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 bye
. If there is no such entity, or ife
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.
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.
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.
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
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
Reputation: 170055
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