18

This code calls &foo::next multiple times

struct foo
{
    foo& next()
    {
        return *this;
    }
};

template<typename Obj>
void tmp_funct_1(Obj& obj)
{}

template<typename Obj, typename Func, typename... Other>
void tmp_funct_1(Obj& obj, Func func, Other... other)
{
    tmp_funct_1((obj.*func)(), other...);
}

now I want to replace recursive calls with one fold expression

Example:

template<typename Obj, typename... Func>
void tmp_funct_2(Obj& obj, Func... func)
{
    (obj .* ... .* func());
}

It doesn't compile because the correct syntax for pointer to member call is

(obj.*func)()

How can I achieve the same result using template fold expression? Thanks!

int main()
{
    foo obj;
    auto to_foo = &foo::next;

    tmp_funct_1(obj, to_foo, to_foo, to_foo);
//  tmp_funct_2(obj, to_foo, to_foo, to_foo);
}

1 Answers1

16

The following code works for a single argument, but not for multiple ones:

template<typename Obj, typename... Func>
void tmp_funct_2(Obj& obj, Func... func)
{
    (obj .* ... .* func)();
}

int main()
{
    foo obj;
    auto to_foo = &foo::next;
    tmp_funct_2(obj, to_foo);
}

The problem is that the fold expression does not expand to a nested invocation of the function pointers like...

(((((obj.*to_foo)().*to_foo)()).*to_foo)());

...but it rather expands to something like...

obj.*func0.*func1.*func2.*func3

...which is not what you want.


Unless you overload operator.*, I think you're stuck with the recursive approach here. Otherwise, you can use some temporary storage and fold over the comma operator:

template<typename Obj, typename... Func>
void tmp_funct_2(Obj& obj, Func... func)
{
    auto* temp = &obj;
    ((temp = &((*temp).*func)()), ...);
}

live example on wandbox.org

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416