c++ why non-static member function is a prvalue?

181 Views Asked by At

I would like too know the rationale behind o.f and o->f being prvalues, where o is an object, and f is a non-static member function.


EDIT 1

My point is that putting it into a prvalue category seems to be tantamount to an ad hoc decision as even though it is not an lvalue in its fullest, it's not yet a complete rvalue also.

  1. g (a regular function) is not assignable, just like f (a non-static member function);
  2. an address of both can somewhat be taken -- though pointer to member function is not required to contain an address, they are sorta semantically close operations. EDIT -- THAT IS NOTED IN COMMENTS THAT IT IS NOT AN ADDRESS OF o.f OR o->f THAT IS TAKEN
  3. member function cannot init lvalue reference, but then it should init rvalue one, but can it?.

And that is odd -- consider point 1) above, only modifiable lvalues are assignable by definition, so lvalue properties are not violated by this "non-assignability". But in 3), all prvalues shall be able to init rvalue references, but a member function can not, presumably.


EDIT 2

I am particularly interested in something like a justification paper from committee people or something like this, showing why it is made this way.

I may be terribly wrong, but I may imagine a hypothetical set of rules that would allow o.f to follow all the behaviors of lvalue. We necessarily need a binding object only for the sake of function call, and technically there is still one definition of the member function in the programm. That seems to be a bit whimsical for me that we cannot trat pointer to non-static member functions exactly like regular function pointers except were call is attempted, where we should provide an argument for a implicit object parameter.

1

There are 1 best solutions below

13
apple apple On

just my guess. In expression o.f(), f is not really a subobject of o, it effectively bind o and f together which can then be called.

which does something like

//------------------------------o.f------------------------------------()
[&](auto&&... args){return x.f(std::forward<decltype(args)>(args)...);}()

except it preserve overloads and (thus) cannot be used in other way (like store in variable).


note that "non-static member function" is pretty different from "pending member function call"

struct X{void f(){}};

void f(){
    auto mfp = &X::f; // you can definitely get member function pointer
    X x;

    x.f(); // x.f is pending member function call
    (x.f)(); // (x.f) is pending member function call
    (x.*mfp)(); // (x.*mfp) is pending member function call

    // [&](auto&&... args){...} is also a prvalue
    [&](auto&&... args){return x.f(std::forward<decltype(args)>(args)...);}();

    // std::bind_fount(&X::f,x) is also a prvalue
    std::bind_front(&X::f,x)(); // but you don't get overloads resolution here
}