vendredi 28 décembre 2018

Expand parameter pack in calling the base types' methods when variadic template class is inherited from template arguments

So basically I want to define a class that inherits from an arbitrary amount of classes and have a method in it that calls the overloaded method from all the base classes.

I tried writing this, but it won't compile:

class Foo
{
public:
    void method()
    {
        std::cout << "Foo::method()\n";
    }
};

class Bar
{
public:
    void method()
    {
        std::cout << "Bar::method()\n";
    }
};

template <typename... Ts>
class Combined: public Ts...
{
public:
    Combined(const Ts&... ts): Ts(ts)... {}
    Combined(Ts&&... ts): Ts(std::move(ts))... {}

    template <typename U>
    void call_methods()
    {
        U::method();
    }

    template <typename U, typename... Us>
    void call_methods()
    {
        U::method();
        call_methods<Us...>();
    }

    void method()
    {
        call_methods<Ts...>();
    }
};


int main(int argc, char *argv[])
{
    Combined<Foo, Bar> obj({}, {});
    obj.method();
    return 0;
}

The compiler says the following:

test.cpp:42:9: error: call to member function 'call_methods' is ambiguous
        call_methods<Us...>();
        ^~~~~~~~~~~~~~~~~~~
test.cpp:47:9: note: in instantiation of function template specialization
      'Combined<Foo, Bar>::call_methods<Foo, Bar>' requested here
        call_methods<Ts...>();
        ^
test.cpp:57:9: note: in instantiation of member function
      'Combined<Foo, Bar>::method' requested here
    obj.method();
        ^
test.cpp:33:10: note: candidate function [with U = Bar]
    void call_methods()
         ^
test.cpp:39:10: note: candidate function [with U = Bar, Us = <>]
    void call_methods()
         ^

Basically there is an ambiguity between call_methods<U = Bar> and call_methods<U = Bar, Us = <>>. But if I declare a void call_methods() {}, it won't match the call_methods<Us...>(); for some reason.

If it's not clear yet, I want Combined<Foo, Bar>::method() to call Foo::method() and Bar::method().

I know that I can probably implement this by having a tuple with the objects of corresponding types as a member and just iterating over them, but I really want to find a solution that's closer to what I wrote.

Aucun commentaire:

Enregistrer un commentaire