Combine capabilities of classes (mixins) with ambiguous calls

  ambiguous-call, c++, mixins, template-mixins, templates

I was reading about the "mixin" technique in C++ but there is something I don’t understand and seems to be a limitation in the language that prevents to do it generically because of ambiguities that the compiler (and the standard refuse to resolve, even if it can).

The idea of mixin is to aggregate capabilities from different parts.
Sometimes the capabilities could be called with the same name because they generically do the same thing.

struct A{
    void f(int){}
};

struct B{
    void f(double){}
};

I could combine the services of the two classes with

struct CombinedAB : A, B{};

However when I use it I get a compilation error: "request for member ‘f’ is ambiguous" (godbolt link).

CombinedAB c; c.f(3.14);  // 3.14 is a double, I expect B::f to be called.

So, the compiler knows that f exists but it refuses to resolve which one is the correct one to call. It generates this error:

main.cpp: In function ‘int main()’:
main.cpp:23:21: error: request for member ‘f’ is ambiguous
     CombinedAB c; c.f(3.14);
                     ^
main.cpp:16:10: note: candidates are: void B::f(double)
     void f(double){}
          ^
main.cpp:12:10: note:                 void A::f(int)
     void f(int){}
          ^

Of course I could change the class and use this idiom "to bring a full fledged version of the f overloads".

struct CombineAB : A, B{
    using A::f;
    using B::f;
};

And it works, but the problem is that the CombineAB cannot be done generically. The closest would be:

template<class T1, class T2>
struct combination : T1, T2{
 // using T1::all_provided_by_T1;
 // using T2::all_provided_by_T2;
};

But I cannot not add the equivalent of using T1::f; using T2::f, first of all because the combination would need to know about all the possible functions in T1, T2.

So it seem that a combination would need to be defined in cases by case basis. For example with

template<class T1, class T2>
struct combination_of_f_service : T1, T2{
  using T1::f; using T2::f;
}

This defeats the purpose because if T1 and T2 provide 20 functions with the same name (as in my case) the class would need to repeat all these functions names. Worst of all it cannot be done via additional template arguments (can it?).

Is this the correct way to combine classes in C++?, is there a workaround or is this simply a too naive view of the problem? I am willing to accept an option involving quite a lot of template code if necessary.


The problem persists even if instantion is not part of the equation and f is a static function.
It seems that the language feels strongly about changing or combining the meaning of member functions in a base class.

Source: Windows Questions C++

LEAVE A COMMENT