Yesterday I came across this question: forcing unqualified names to be dependent values . Initially, this seemed like a very specific issue related to the violated behavior of VC ++, but when I tried to solve this problem, I came across a virtual inheritance pattern that I had not encountered before (I will explain this in a second after I tell you about my question). I found this interesting, so I searched it on SO and Google, but I could not find anything. Maybe I just don’t know the right name for him (the “injection method” was one of my guesses), and this is actually widely known. This is also part of my question for the community: Is this a common use pattern or a special case of another well-known paradigm? Do you see problems / traps that can be avoided with another solution?
The problem this template can solve is this: suppose you have a Morph class with the doWork() method. Inside doWork() , several functions are called, the implementation of which must be selected by the user (therefore, the class is called Morph ). Let me call those called functions chameleons (since the Morph class does not know what they will be in the end). Of course, one way to achieve this would be to make the chameleons virtual methods of the Morph class, so the user can get from Morph and override the selected methods. But what if the user has to use different combinations to select an implementation for different chameleons. Then, for each combination, a new class must be defined. Also, what if there are several Morph classes where the same functions should be chameleons? How can a user reuse a replacement that she has already implemented?
Regarding the problem of “multiple classes to be defined,” the patterns immediately jump into one mind. Could the user choose the chameleon implementations that he wants, passing the classes as template parameters that define the desired implementation? That is, something like Morph<ReplaceAB> , which should effectively replace the chameleons A() and B() in doWork() with some implementation, leaving other chameleons, such as C() possible, untouched. With C ++ 11 and variable templates, even combinations will not be a problem: Morph<ReplaceAB, ReplaceC, WhateverMore...> Well, this is exactly what this template can do (see the explanation below):
The output of which is as follows:
Default A Default B Default C Alternative A Alternative B Default C Default A Default B Alternative C Alternative A Alternative B Alternative C
Seeing this working solution, the problem with the above idea is actually not so obvious: Morph could not get only the classes specified as template parameters, so the chameleons A() , B() and C() just taken from what Morph inherits ? This is actually impossible, since chameleon calls are independent of template parameters, and such name-independent names are not visible in dependent inherited classes (try if you like). This means that we need to somehow make sure that the call of the chameleon is associated with something that can subsequently be replaced by the desired implementation.
What happens with virtual inheritance: By Morph inheriting from Chameleons (independent of template parameters), an unqualified chameleon calls doWork() , bound to virtual functions in Chameleons . Since Morph and Replacement classes actually inherit from Chameleons , only one Chameleons object will exist in any Morph object, and virtual function calls will be sent at runtime to be implemented in the most derived class, which we push through template inheritance. Thus, although unqualified chameleon names in doWork() cannot be resolved to the desired implementation at compile time (in accordance with the standard), they can still be called by an indirect layer through a virtual base class. Funny huh? (If you do not tell me that it is much easier to do it differently or the template is widely known.)