3

Suppose I have the following:

struct A {
  int foo(int bar) const { return bar; }
};

and I want to specify a name that refers to a "bound" member function (i.e.):

A a;
auto opt1 = a.foo; // Forbidden, instead do something like...
auto opt2 = [&a] (int i) { return a.foo(i); }; // or ...
auto opt3 = std::bind(&A::foo, a, std::placeholders::_1);

it is then simple to invoke the bound member function:

assert(opt1(42) == 42); // If 'opt1' were allowed
assert(opt2(42) == 42); 
assert(opt3(42) == 42);

In my view, opt1 would be the preferred solution to achieve the goal. However, specifying a bound function via opt1 is forbidden by the language.

My question is purely legal: What part of the C++(20) standard forbids a construct like opt1? My question is not why, but where.

KyleKnoepfel
  • 1,426
  • 8
  • 24
  • 3
    [Pointers to member functions are not actually pointers](https://stackoverflow.com/questions/72167059/are-pointers-to-non-static-member-function-formally-not-considered-pointers). They have their own syntax like `&A::foo`. Also, a member function doesn't implicitly decay to pointer to member function unlike ordinary free function. – Jason Aug 15 '22 at 17:02
  • 1
    https://timsong-cpp.github.io/cppwp/n4861/expr.ref#6.3.2 – Language Lawyer Aug 15 '22 at 17:03
  • From [basic.compund#3](https://timsong-cpp.github.io/cppwp/n4659/basic.compound#3) *"Except for pointers to static members, text referring to “pointers” does not apply to pointers to members"* so whatever you assumed about `a.foo` is not true. – Jason Aug 15 '22 at 17:05
  • I'm not sure why you think this it must to be forbid. It can simply not be a thing like whatever new feature you want. – apple apple Aug 15 '22 at 17:06
  • @appleapple No, it's explicitly forbidden. – Sneftel Aug 15 '22 at 17:06
  • 1
    The syntax you want is: `auto opt1 = &A::foo;` Then it would be called like `(a.*opt1)(42)`. – Martin York Aug 15 '22 at 17:06
  • @Sneftel I mean OP seems to think anything not explicitly forbit is allowed and has meaningful result. – apple apple Aug 15 '22 at 17:07
  • @JasonLiam, I didn't assume anything about `a.foo`--I simply wondered where in the standard such a construct was forbidden. Notice I use the term *name* to specify a bound function, as clearly `opt2` and `opt3` are not pointers. – KyleKnoepfel Aug 15 '22 at 17:08
  • @MartinYork, no `auto opt1 = &A::foo` does not specify a *bound* member function. To bind it to `a`, you would then need to do `(a.*opt1)(42)`. – KyleKnoepfel Aug 15 '22 at 17:10
  • Note that the compiler error is: **cannot convert 'A::foo' from type 'int (A::)(int) const' to type 'int (A::*)(int) const'** So `a.foo` seems to be just fine. It's just not an object that can be bound to a name. – Goswin von Brederlow Aug 15 '22 at 17:10
  • 1
    @KyleKnoepfel In general there shouldn't be an expectation that something has to be expressly forbidden to not be allowed. Something can be disallowed by omission. – François Andrieux Aug 15 '22 at 17:10
  • @KyleKnoepfel That's because `foo` is not a member of the objext `a` it is a member of the class `A`. You have to explicitly bind `a` seprately like you have done with `opt2` and `opt3`. – Martin York Aug 15 '22 at 17:12
  • 1
    @FrançoisAndrieux, sure, I understand that. But `a.foo` is so much simpler (in syntax) than the other options that it seemed to me likely that it probably was disallowed...and @Sneftel has found that it is. – KyleKnoepfel Aug 15 '22 at 17:12
  • Note2: `&a.foo` yields **ISO C++ forbids taking the address of a bound member function to form a pointer to member function. Say '&A::foo' [-fpermissive]** which is probably a better thing to look for in the standard. – Goswin von Brederlow Aug 15 '22 at 17:12
  • 1
    BTW, `opt2`&`opt3` are not equivalent, one bind by reference, and the later bind by copy (both have syntax to allow the other way). Not sure how `opt1` would have the 2 ways of binding... – Jarod42 Aug 15 '22 at 17:23
  • 2
    In C++20, another alternative: `auto opt4 = std::bind_front(&A::foo, a);`. – Jarod42 Aug 15 '22 at 17:24
  • 1
    You could reskin the syntax of C++ to make the syntactic sugar more to your liking. Such as the [SPECS](https://users.monash.edu/~damian/papers/HTML/ModestProposal.html) (by Werther & Conway) and [Carbon](https://github.com/carbon-language/carbon-lang) efforts. Or you could make your own C++ syntax reskin. I'm working on one myself, just for fun. – Eljay Aug 15 '22 at 17:29

1 Answers1

5

[expr.ref]:

[for the expression E1.E2]....if E1.E2 refers to a non-static member function...The expression can be used only as the left-hand operand of a member function call.

Sneftel
  • 40,271
  • 12
  • 71
  • 104