6

I have a situation in which I want a member function pointer to a virtual function that avoids dynamic dispatch. See below:

struct Base
{
    virtual int Foo() { return -1; }
};

struct Derived : public Base
{
    virtual int Foo() { return -2; }
};

int main()
{
    Base *x = new Derived;

    // Dynamic dispatch goes to most derived class' implementation    
    std::cout << x->Foo() << std::endl;       // Outputs -2

    // Or I can force calling of the base-class implementation:
    std::cout << x->Base::Foo() << std::endl; // Outputs -1

    // Through a Base function pointer, I also get dynamic dispatch
    // (which ordinarily I would want)
    int (Base::*fooPtr)() = &Base::Foo;
    std::cout << (x->*fooPtr)() << std::endl; // Outputs -2

    // Can I force the calling of the base-class implementation
    // through a member function pointer?
    // ...magic foo here...?

    return 0;
}

For the curious, the reason I want this is because the derived class implementation is using a utility class to memoize (add a cache around) the base-class implementation. The utility class takes a function pointer but, of course, the function pointer dispatches dynamically to the most derived class and I get an infinite recursion.

Is there a syntax that allows me to reproduce the static dispatch behaviour I can achieve with x->Base::foo() but through a function pointer?

SimonD
  • 638
  • 5
  • 16

2 Answers2

1

You could force the slicing of the Base* like this:

std::cout << (static_cast<Base>(*x).*fooPtr)() << std::endl; // Outputs -1
TartanLlama
  • 63,752
  • 13
  • 157
  • 193
  • 1
    Interesting... but this actually calls the Base copy constructor so is only applicable in some cases. If Base has a private copy constructor or any pure virtual functions, this solution won't apply. – SimonD Apr 21 '15 at 08:17
0

There's no free-standing "member function pointer" with the property you want. The closest thing to a bound member function is a closure:

Base * x = new Derived;
auto f = [x]() { x->Base::Foo(); }
f();

If your class Base is a special, one-off use-case and is under your control, you should probably add some kind of "accept visitor" function to it so you can pass in member callers dynamically, like x->accept(foo_caller); etc. An example in C++14:

struct X
{
    template <typename F>
    auto accept(F && f)
    {
        return [this, &f](auto &&... args) {
            return f(this, std::forward<decltype(args)>(args)...); };
    }

    virtual void foo() const { std::cout << "base\n"; }
};

Usage:

void call_static_foo(X * p)
{
    p->accept([](X * that){that->X::foo();});
}
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • [Demo](http://ideone.com/h4QXUi). – Kerrek SB Apr 21 '15 at 08:33
  • I can imagine how a lambda would help but I don't understand the purpose of 'accept'...? Also the demo prints 'derived', whereas I want 'base'... am I missing something? – SimonD Apr 21 '15 at 10:46
  • In the demo, the returned functor needed to be called: `p->accept([](X * that){that->X::foo();})();` Prints base as expected. Still not sure what advantage is being gained from accept though, could you talk me through it? – SimonD Apr 21 '15 at 10:55
  • @SimonD: well, I was thinking that if you originally had the desire to use function pointers, then you want a mechanism for deciding the dispatch target *dynamically*. The `accept` construction allows for that, too, e.g. you could make a container of visitors and then randomly accept one of them. – Kerrek SB Apr 21 '15 at 11:24