Using and disadvantages of C ++ template parameters defining base classes of a class?

Background

I recently thought about how to create a specific piece of software, and at some point I created the following snippet below:

template <typename ... Mixins>
class Foo : public virtual Mixins... {
    /* ... */
};

The idea that I had was the ability to increase the base class with additional properties or behavior depending on the needs of the user. Say that one application should use Foowith an identification number. Perhaps some other application should be able to talk about Foowith color. These needs can be met by adding the following classes:

class HasID {
    int m_id = -1;

public:
    int getID() { return m_id; }
    void assignID(int id) { m_id = id; }
};

class HasColor {
public:
    int color = 0;
};

Questions

My two questions about this code are as follows:

  • What are the advantages and disadvantages of using such patterns?
  • Does this particular template have a name?

Additional Code

, .

:

// Default printBase
template <typename Base>
void printBase(std::ostream& out, Base& x) {}

// printBase for HasID
template <>
void printBase(std::ostream& out, HasID& x) {
    out << ", ID=" << x.getID();
}

// printBase for HasColor
template <>
void printBase(std::ostream& out, HasColor& x) {
    out << ", color=" << x.color;
}

// Recursive step of printBases
template <typename Derived, typename Base, typename ... Bases>
void printBases(std::ostream& out, Derived& x, Base& y) {
    printBase(out, y);
    printBases<Derived, Bases...>(out, x, x);
}

// Base case of printBases    
template <typename Derived>
void printBases(std::ostream& out, Derived& x, Derived& y) {}

// ostream operator
template <typename ... Mixins>
std::ostream& operator<<(std::ostream& out, Foo<Mixins...>& x) {
    out << "<Foo";
    printBases<Foo<Mixins...>, Mixins...>(out, x, x);
    return out << '>';
}

Main:

int main()
{
    Foo<> plainFoo;
    Foo<HasID> fooWithID;
    fooWithID.assignID(42);
    Foo<HasID, HasColor> multiTalentedFoo;
    multiTalentedFoo.assignID(1234);
    multiTalentedFoo.color = 0xff0000;

    std::cout
        << plainFoo << '\n'
        << fooWithID << '\n'
        << multiTalentedFoo << '\n';
}

:

<Foo>
<Foo, ID=42>
<Foo, ID=1234, color=16711680>
+4

Source: https://habr.com/ru/post/1649242/


All Articles