Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I prefer mixins or function templates to add behavior to a set of unrelated types?

Mixins and function templates are two different ways of providing a behavior to a wide set of types, as long as these types meet some requirements.

For example, let's assume that I want to write some code that allows me to save an object to a file, as long as this object provides a toString member function (this is a rather silly example, but bear with me). A first solution is to write a function template like the following:

template <typename T>
void toFile(T const & obj, std::string const & filename)
{
    std::ofstream file(filename);
    file << obj.toString() << '\n';
}
...
SomeClass o1;
toFile(o1, "foo.txt");
SomeOtherType o2;
toFile(o2, "bar.txt");

Another solution is to use a mixin, using CRTP:

template <typename Derived>
struct ToFile
{
    void toFile(std::string const & filename) const
    {
        Derived * that = static_cast<Derived const *>(this);
        std::ofstream file(filename);
        file << that->toString() << '\n';
    }
};

struct SomeClass : public ToFile<SomeClass>
{
    void toString() const {...}
};
...
SomeClass o1;
o.toFile("foo.txt");
SomeOtherType o2;
o2.toFile("bar.txt");

What are the pros and cons of these two approaches? Is there a favored one, and if so, why?

like image 623
Luc Touraille Avatar asked Dec 27 '22 07:12

Luc Touraille


2 Answers

The first approach is much more flexible, as it can be made to work with any type that provides any way to be converted to a std::string (this can be achieved using traits-classes) without the need to modify that type. Your second approach would always require modification of a type in order to add functionality.

like image 151
Björn Pollex Avatar answered Dec 30 '22 09:12

Björn Pollex


Pro function templates: the coupling is looser. You don't need to derive from anything to get the functionality in a new class; in your example, you only implement the toString method and that's it. You can even use a limited form of duck typing, since the type of toString isn't specified.

Pro mixins: nothing, strictly; your requirement is for something that works with unrelated classes and mixins cause them to be become related.

Edit: Alright, due to the way the C++ type system works, the mixin solution will strictly produce unrelated classes. I'd go with the template function solution, though.

like image 25
Fred Foo Avatar answered Dec 30 '22 11:12

Fred Foo