Function References

So I was just working with function pointers and I remembered that you could do this:

void Foo()
{
}

int main()
{
    void(& func)() = Foo;

    func(); //::Foo();
}

The obvious advantage being that references reference valid objects (unless they're misused), or functions in this case.

The obvious disadvantages being that you can't store an array of references and can't use them for member function pointers (at least as far as I can tell).

My question: does anyone use them (i.e., function references, not function pointers), and if so, in what scenarios have you found them useful/helpful?

The only place I can see them being useful off the bat is binding a reference to a certain function when working with conditional compilation.


Solution 1:

I've used them before to add customization to classes by passing them to the constructor in a way like the strategy pattern

Solution 2:

I think your example usage is quite good. Because if you would use an ordinary function pointer, and you then apply the address-of operator, you would get the address of the function pointer. Using a reference to function will do the expected thing, in that it returns a pointer to the function itself.

I also can't think of many examples. Keeping function references, as you point out, has some ugly consequences. Another possibly unwanted consequence is, if kept as a class-member, your objects will be non-assignable if you don't write your own operator= and refrain from trying to re-assign the function-reference.

I think most uses of function references are implicit, much like most uses of array-references - although much more so, when you accept arguments by-reference:

template<typename T>
void do_something(T const& t) { ... }

While accepting arrays by reference has the advantage of not losing their size information, accepting functions by reference explicitly doesn't seem to have an advantage (at least as far as I can see). I suppose the existence of function references largely is justified by the idealistic view of a reference as an alias-name of some object or function, together with the fact that it allows passing functions to such templates that accept their argument by reference.

I would probably avoid using them if I wouldn't need them inevitably. Constant function pointers also provide non-reassignable callables, and will probably avoid confusions when other programmers, who possibly are not very familiar with this language niches, read your code. Worth to note that Vandervoorde & Josuttis also recommend to avoid them to reduce confusion (in their book C++ Templates - The Complete Guide).

Solution 3:

Function references, unlike function pointers, make it harder to create them from an invalid source. This is useful if you are making a wrapper around a C library - the C++ code can take a callback function by reference and pass the pointer to the C library if the lbrary requires that the passed pointer must not be NULL.

It is also a convenient way to alias a function, especially in C++11 with the new auto keyword:

#include <iostream>
#include <typeinfo>

void f(int i, char c)
{
    std::cout << i << ' ' << c << std::endl;
}

int main()
{
    std::cout << typeid(f).name() << std::endl; //FvicE
    f(0, '1');

    void (*pf)(int, char) (&f); //ugly
    std::cout << typeid(pf).name() << std::endl; //PFvicE
    (*pf)(2, '3');
    pf(4, '5'); //works, but I don't recommend it

    void (&rf)(int, char) (f); //still ugly
    std::cout << typeid(rf).name() << std::endl; //FvicE
    rf(6, '7');

    auto &af (f); //pretty, but only works in C++11
    std::cout << typeid(af).name() << std::endl; //FvicE, same as above
    af(8, '9');
}

Solution 4:

in addition to the use as strategy (as pointed out by Robert Gould), I freqently use them at the entrance point to (template) metaprogramming. A function reference can easily be picked up by a template parameter; from this point on it can be passed through several layers of (metaprogramming) templates. Of course, this holds true for a function pointer as well, but the reference is an alias and thus communicates the intention more clearly.

To give an example: when writing a generic command dispatching system for an application, a lot of different operations need to be announced as commands. We can use a simple "builder function" as front-end for the client code. Behind the scenes, this builder function picks up the actual function signature as template parameter, derives (by template metaprogramming) the actual parameter and return type values and possibly picks the suitable specialisation to store a "memento" and an "undo functor". These functors can than be stored either as function pointers internally, or using boost or tr1 or C++11 function objects. This way, it is possible to build a type safe command invocation and "undo" system.