Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overload resolution without a parameter list on class member access?

Tags:

c++

c++11

struct X
{
    void f(double) {}
    static void f(int) {}
};

int main()
{
    X x;

    auto y = x.f;
}

gcc gives:

error: unable to deduce ‘auto’ from ‘x.X::f’

x.f is a class member access postfix-expression documented in 5.2.5 [expr.ref]

It effectively says:

If f is a (possibly overloaded) member function, function overload resolution (13.3) is used to deter- mine whether x.f refers to a static or a non-static member function. (from N3485 5.2.5.4.3 )

How can overload resolution be applied here - x.f doesn't have a parameter list with which to do overload resolution?

Or am I missing something?

Update: If I change the auto y = x.f line to an expression-statement:

- auto y = x.f;
+ x.f;

then gcc instead complains:

error: statement cannot resolve address of overloaded function
like image 207
Andrew Tomazos Avatar asked Feb 12 '26 23:02

Andrew Tomazos


2 Answers

I think you're right in that the Standard isn't precise at this point:

[expr.ref]/4

If f is a (possibly overloaded) member function, function overload resolution (13.3) is used to determine whether x.f refers to a static or a non-static member function.

As the first sub-bullet states:

If it refers to a static member function and the type of E2 is “function of parameter-type-list returning T”, then E1.E2 is an lvalue; the expression designates the static member function. The type of E1.E2 is the same type as that of E2, namely “function of parameter-type-list returning T”.

That is, x.f can be used to initialize a function ptr if f is static, whereas (see following sub-bullet) if f is not static, it can only be used in a function-call expression.

But actually, overload resolution is not performed to select an overload from the name of an overloaded function outside the context of a function-call-expression:

[over.over]/1

A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set. [...] The function selected is the one whose type is identical to the function type of the target type required in the context.

That is, an exact match, not invoking the overload resolution mechanism described in [over.match]. Therefore [expr.ref]/4 is incomplete, is doesn't describe your case of using x.f to initialize a function pointer/reference.

As the auto keyword doesn't specify a target type (or according to [dcl.spec.auto]/6, the mechanism to deduce the type for auto fails), you cannot use auto y = x.f;:

  • x.f refers to a set of overloaded functions
  • a function from this set needs to be selected
  • selection is based upon overload resolution (in a function-call-expression, not applicable here) or based on the target type
  • there's no target type here, or rather, the target type is equivalent to a template argument, therefore type deduction for auto fails

The type of x.f therefore is

  • in the context of a function call, directly refer to [expr.ref]/4
  • otherwise, it is a set of overloaded functions, from which then the function is selected according to [over.over], whereupon the type is determined according to [expr.ref]/4
like image 110
dyp Avatar answered Feb 16 '26 11:02

dyp


Even if there's only one x.f valid in this context, the compiler must do the overload resolution before determining if the function is static or not.

§5.2.5 « If E2 is a (possibly overloaded) member function, function overload resolution (13.3) is used to determine whether E1.E2 refers to a static or a non-static member function. »

The overload resolution mechanism (as described in §13.3 and §13.4) need a valid context to select the correct candidate :

§13.4.1 « A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set »

auto y = x.f; is not a valid resolution context, you either have to drop the auto keyword or to use a static_cast to force the overload resolution :

X x;

auto y = static_cast<void (&)(int)>(x.f);
y(1);

auto z = static_cast<void (X::*)(double)>(&X::f);
(x.*z)(1.);

Note that you can't have a reference to a non-static member, only a pointer, as per § 8.3.3 :

There is no “reference-to-member” type in C++

like image 39
zakinster Avatar answered Feb 16 '26 11:02

zakinster



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!