43

In C++ I can chose between function pointers and function references (or even function values for the sake of completeness):

void call_function_pointer (void (*function)()) {
    (*function) ();
}
void call_function_reference (void (&function)()) {
    function ();
}
void call_function_value (void function()) {
    function ();
}

When it comes to methods however, I don't seem to have this choice between pointers and references.

template <class T> void call_method_pointer (T* object, void (T::*method)()) {
    (object->*method) ();
}
// the following code creates a compile error
template <class T> void call_method_reference (T& object, void (T::&method)()) {
    object.method ();
}

This leads me to the assumption that method references do not exist in C++. Is that true? If it is, what is the reason they do not exist?

Jason C
  • 38,729
  • 14
  • 126
  • 182
eyelash
  • 3,197
  • 25
  • 33
  • 8
    You are correct that method references do not exist. The C++ standard doesn't define such a type, and explicitly states (in a non-normative note) when it describes pointer-to-member types, "There is no "reference-to-member" type in C++." But I cannot answer your question about the reason they do not exist. –  Feb 22 '14 at 09:43
  • possible duplicate of [Reference to member function?](http://stackoverflow.com/questions/7245404/reference-to-member-function) – Etherealone Feb 22 '14 at 10:07
  • @Etherealone Almost a duplicate except this question adds the additional "why?" – Jason C Feb 22 '14 at 10:08
  • Since methods belongs to an instance it doesn't make sense to pass them as pointers – Joatin Feb 22 '14 at 10:19
  • 1
    @Tintin Yes it does (and they are just pointers to vtable entries). That's exactly what the pointer-to-member operators `.*` and `->*` are for. The question here is why is there no reference-to-member equivalents, even though object references and function reference exist. Even on c.l.c++, there a multiple discussions that dead-end as soon as somebody asks "why". I'm personally very curious about the rationale, I'm sure it is buried in some draft comments somewhere. – Jason C Feb 22 '14 at 10:27
  • You can think of an object as a pointer to a table of member methods. Why would you want to take reference (or pointer) to one of member methods while you already have the pointer to the table? You will need to pass `this` to the method somehow, so you can directly use this. This is probably not the way you want to create an abstraction/consistent interface for multiple classes (which is what you are trying I think). Use inheritance. – Etherealone Feb 22 '14 at 11:41
  • 1
    @Etherealone For the same reason you would take a reference to data or a function instead of a pointer. Whether or not references are truly necessary is a different debate... but the original rationale for references, at least according to 1989 CFront, is (paraphrased) "combining value semantics with pointer efficiency". The OP's question is interesting: Pointers to data, objects, functions, and members exist. References to data, objects, and functions exist -- but references to members don't exist and, purely out of curiosity, I wonder why (plus C++ very explicitly omits it). – Jason C Feb 22 '14 at 11:51
  • 2
    (In other words: The question isn't "Why do you need this?" or "Is there an alternative?", the question is "Why are these conspicuously absent?" It is an academic question, not necessarily a practical one.) – Jason C Feb 22 '14 at 11:55
  • One note about "or even function values for the sake of completeness": This is wrong, there are no function values. The expression that syntactically stands for a function type as "value", in any context that is not the definition of that same function (unless I'm missing out something unusual), decays to a pointer to a function of that type. In your example, `void call_function_value (void function()) {...` actually means: `void call_function_value (void (*function)()) {...` In other words, the actual type of "call_function_value" is `void (void(*)())` – R.G. Feb 21 '18 at 20:24

1 Answers1

53

In the standard (e.g. N3337 - not the latest but fine for this) there is a note at the end of section 8.3.3.3 that reads:

[ Note: See also 5.3 and 5.5. The type “pointer to member” is distinct from the type “pointer”, that is, a pointer to member is declared only by the pointer to member declarator syntax, and never by the pointer declarator syntax. There is no “reference-to-member” type in C++. — end note ]

Also, of course, there are no "reference to member" type operators (which, hypothetically, the best I can come up with would be something like ->& and .&, although these are not consistent with dereferencing of data and function references, which require no special operator).

Why?

As for why; after a fun little historical investigation and failing to find any existing notes on it (I went all the way back to Cfront 2.0 where pointer-to-member was first supported -- edit: according to a far more credible document, the feature was actually first supported in Cfront 1.2), I asked the man himself and here is the reply:

Date: Sat, 22 Feb 2014 10:12:51 -0500
From: Bjarne Stroustrup <...>
Subject: Re: On lack of reference-to-member and CFront 2.0

On 2/22/2014 6:40 AM, Jason C wrote:
> My question is: C++ very clearly disallows the concept of 
> "reference-to-member". Why is this? I have been doing a lot of 
> research, and I traced the origin of "pointer-to-member" back (I 
> think) to 1989 CFront 2.0. I read through the product reference manual 
> and other documentation hoping to find an explanation of some sort but 
> could not.

I don't really remember. It was 25+ years ago and the ARM is silent on 
this. I added pointers to members to eliminate the need for a rare 
breakage of the type system. I suspect that I didn't add references to 
members because it did not seem worth the effort: there was no use case.

To be honest, I was expecting something far more arcane and complicated.

So there you have it: The next time somebody asks why there's no reference-to-member, you can confidently say, "Because there isn't!" (Note: See my ramblings in the comments; there is still some historical investigation to be done to get to 100% confidence.)

Personally, I've never once found a use for pointers-to-members in my own code, but a distinct rationale for their existence is given in Stroustrup's The Evolution of C++: 1985-1989, pp. 222-223.


By the way, your syntax for calling the hypothetical reference-to-member function:

object.method();

... does not make much sense, as there is no way to distinguish that syntactically from a call to an actual member named method().

hvd brings up a good point below: As you can see from the above, syntactically, there wouldn't really be a consistent way to dereference a reference-to-member. You have to distinguish it from normal member access, but at the same time you want to make it consistent with dereferencing of object and function references (which require no special operator), and I can't really think of anything that accomplishes both.

Jason C
  • 38,729
  • 14
  • 126
  • 182
  • 6
    Your "By the way" note should be your answer, IMO. Separate `->&` and `.&` operators would be useless, a large benefit of references is that you don't need to dereference them like you do pointers, and your last note explains perfectly well why that wouldn't work. –  Feb 22 '14 at 10:10
  • @hvd That is a good point; I wonder if the resulting syntactic ambiguity was the original rationale for disallowing it. There really wouldn't be any other consistent way to dereference the reference; everything would be a special case just for reference-to-members. – Jason C Feb 22 '14 at 10:30
  • 1
    my 2¢: a reference is a name for a given entity. The name of a member cannot be used by itself (except with an implicit `this->`), so it would be useless to create an alias. – Potatoswatter Feb 22 '14 at 12:32
  • @Potatoswatter: See update. Looks like "because it's useless" is the winner! – Jason C Feb 22 '14 at 17:22
  • 1
    Stroustrup mentioned in a later reply, "Actually, there was/is a Bell Labs Technical Memorandum that may shed light, but I don't have it handy." -- I am currently on a mission to find and obtain this and will update here if and when I do. I don't know if there is an archive online, I'm crossing my fingers that Alcatel-Lucent has the documents and is willing to share. – Jason C Feb 22 '14 at 18:35
  • [This paper](http://www.stroustrup.com/hopl2.pdf) states, *"Releases 1.1 (June 1986) and 1.2 (February 1987) were primarily bug fix releases but also added pointers to members and protected members (§4.1)."* Earlier, in reference to pointers-to-members, it states, *"The main features of 2.0 were first presented in [Stroustrup,1987c] and summarized in the revised version of that paper [Stroustrup,1989b]"*. 1987c is *The Evolution of C++: 1985− 1987* from a 1987 USENIX conference. I am trying to locate that document as well. – Jason C Feb 22 '14 at 18:56
  • I found the [1989b paper in the USENIX archives](https://www.usenix.org/legacy/publications/compsystems/1989/sum_stroustrup.pdf) but so far I cannot locate the 1987 paper. The 1989 paper does not shed light on lack of references but does state that pointers to members are described in greater detail in *Stan Lippman and Bjarne Stroustrup, Pointers to Members in C++, Proc. USENIX C++ Conference, Denver, October 1988.* So that's two USENIX documents to look for. The 1988 conference proceedings seem hard to come by. – Jason C Feb 22 '14 at 19:10
  • I still have not been able to obtain the mentioned documents, but I haven't forgotten. – Jason C Mar 03 '14 at 21:22
  • @JasonC, 2 and half years later - any luck? :) – SergeyA Jun 01 '16 at 16:45
  • IMO, since the parentheses are required when calling a pointer-to-member function, they should be required when calling the hypothetical "reference-to-member" `(object.method)()`. Unless the "reference-to-member" was also a member of the class, then, the syntax `object.method()` would make sense as it's just an alias to another member of the object. – user666412 Feb 03 '17 at 20:30
  • But I agree it would be just some (nice) syntactic sugar (again, useless). – user666412 Feb 03 '17 at 20:40
  • @user666412 Adding parentheses would do nothing to remove the fatal ambiguity of such an expression. `(object.member_function)(args)` is equivalent to `object.member_function(args)`. So, we never got away from Square 1. – underscore_d Nov 17 '18 at 10:38
  • You can put parentheses around a pointer-to-member function: `(object.*(ptr_to_mem_fn))(args)` because the expression for the pointer-to-member function can be arbitrarily complex; but you cannot put parentheses around the a regular member function name: `object.(mem_fn)(args)` does not parse. So, for a hypothetical reference-to-member function `ref_to_mem_fn`, there’s the syntax `object.(ref_to_mem_fn)(args)` available. – Quirin F. Schroll Mar 31 '22 at 12:39
  • @SergeyA 8 years later (wth): nope. Lol. – Jason C Nov 10 '22 at 04:10
  • 1
    Jason C: I have "C++ Gems 1 & 2" and they refer to former papers, so maybe they might be in there. I would have to check. – SJHowe May 30 '23 at 13:52