C++ mixin constructor arguments
<p>I'm currently experimenting with the implementation of mixin classes in C++. I almost have the behavior that I want. However there's one issue concerning the passing through of the mixin's base class arguments: If the base class requires a const reference to a non-copyable object then the code fails to compile.</p>

<p>As you can see in the code sample below. The class <code>WidgetBase</code> compiles fine and <code>MetaWidgetBase</code> gets a compiler error:</p>

<pre><code>#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;typeinfo&gt;

class WidgetBase
{
public:
    WidgetBase(WidgetBase * inParent, const std::string &amp; inTitle) :
        mParent(inParent),
        mTitle(inTitle)
    {
    }

    virtual ~WidgetBase() { }

private:
    WidgetBase * mParent;
    std::string mTitle;
};

class MetaWidgetBase
{
public:
    MetaWidgetBase(const std::type_info &amp; inTypeInfo) : mTypeInfo(inTypeInfo) {}

    virtual ~MetaWidgetBase(){}

private:
    const std::type_info &amp; mTypeInfo;
};

template&lt;class SuperType&gt;
class Resizable : public SuperType
{
    typedef SuperType Super;

public:
    void resize(int width, int height) {}

protected:
    Resizable() {}

    template&lt;class Arg0&gt;
    Resizable(Arg0 arg0) : Super(arg0) {}

    template&lt;class Arg0, class Arg1&gt;
    Resizable(Arg0 arg0, Arg1 arg1) : Super(arg0, arg1) {}

    template&lt;class Arg0, class Arg1, class Arg2&gt;
    Resizable(Arg0 arg0, Arg1 arg1, Arg2 arg2) : Super(arg0, arg1, arg2) {}

    template&lt;class Arg0, class Arg1, class Arg2, class Arg3&gt;
    Resizable(Arg0 arg0, Arg1 arg1, Arg2 arg2, Arg3 arg3) : Super(arg0, arg1, arg2, arg3) {}
};

template&lt;class SuperType&gt;
class Movable : public SuperType
{
    typedef SuperType Super;

public:
    void move(int x, int y) {}

protected:
    Movable() {}

    template&lt;class Arg0&gt;
    Movable(Arg0 arg0) : Super(arg0) {}

    template&lt;class Arg0, class Arg1&gt;
    Movable(Arg0 arg0, Arg1 arg1) : Super(arg0, arg1) {}

    template&lt;class Arg0, class Arg1, class Arg2&gt;
    Movable(Arg0 arg0, Arg1 arg1, Arg2 arg2) : Super(arg0, arg1, arg2) {}

    template&lt;class Arg0, class Arg1, class Arg2, class Arg3&gt;
    Movable(Arg0 arg0, Arg1 arg1, Arg2 arg2, Arg3 arg3) : Super(arg0, arg1, arg2, arg3) {}
};


class MyWidget : public Resizable&lt;Movable&lt;WidgetBase&gt; &gt;
{
    typedef Resizable&lt;Movable&lt;WidgetBase&gt; &gt; Super;

public:
    MyWidget(WidgetBase * inParent, const std::string &amp; inTitle) :
        Super(inParent, inTitle)
    {
    }
};


class MyMetaWidget : public Resizable&lt;MetaWidgetBase&gt;
{
    typedef Resizable&lt;MetaWidgetBase&gt; Super;

public:
    MyMetaWidget() :
        Super(typeid(this))
    {
    }
};

int main()
{
    // Works fine:
    MyWidget widget(NULL, "Hello");

    // Error: std::type_info has private copy constructor!
    MyMetaWidget metaWidget;

    return 0;
}
</code></pre>

<p>Exact error message is:</p>

<pre><code>/usr/include/c++/4.2.1/typeinfo: In constructor 'MyMetaWidget::MyMetaWidget()':
/usr/include/c++/4.2.1/typeinfo:135: error: 'std::type_info::type_info(const std::type_info&amp;)' is private
</code></pre>

<p>My current workaround is to pass the std::type_info object as a const pointer instead of a const reference.</p>

<p>Does anyone how to handle this problem properly?</p>

<h2>Update</h2>

<p>It seems that during the forwarding the template arguments only loose the reference  part of their type signature. The rest remains unharmed. This also implies that if we use "ArgN &amp;" as argument type, we are safe.</p>

<p>So basically the solution is this: have the constructor of the mixin class take all its arguments as non-const references.</p>

<p>Here's my sample application that tests various combinations(GCC):</p>

<pre><code>#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;typeinfo&gt;

#define TRACE std::cout &lt;&lt; __PRETTY_FUNCTION__ &lt;&lt; std::endl &lt;&lt; std::flush;
#define TRACE_MIXIN std::cout &lt;&lt; __PRETTY_FUNCTION__ &lt;&lt; std::endl &lt;&lt; std::flush;
#define TRACE_BASE std::cout &lt;&lt; "\n" &lt;&lt; __PRETTY_FUNCTION__ &lt;&lt; std::endl &lt;&lt; std::flush;

// Savable is a mixin class for saving object state to file.
template&lt;class BaseType&gt;
struct Savable : public BaseType {
    Savable() {
        TRACE_MIXIN
    }

    template&lt;class Arg0&gt;
    Savable(Arg0 &amp; arg0) : BaseType(arg0) {
        TRACE_MIXIN
    }

    template&lt;class Arg0, class Arg1&gt;
    Savable(Arg0 &amp; arg0, Arg1 &amp; arg1) : BaseType(arg0, arg1) {
        TRACE_MIXIN
    }

    void Save(const std::string &amp; inFileName) {}
};

// Loadable is a mixin class for load object state from file.
template&lt;class BaseType&gt;
struct Loadable : public BaseType {
    Loadable() {
        TRACE_MIXIN
    }

    template&lt;class Arg0&gt;
    Loadable(Arg0 &amp; arg0) : BaseType(arg0) {
        TRACE_MIXIN
    }

    template&lt;class Arg0, class Arg1&gt;
    Loadable(Arg0 &amp; arg0, Arg1 &amp; arg1) : BaseType(arg0, arg1) {
        TRACE_MIXIN
    }

    void Load(const std::string &amp; inFileName) {}
};

// Test with a copyable constructor args
namespace CopyLand {

struct MyObject  {}; // copyable

struct ValueBase {
    ValueBase(MyObject inObject, const std::string &amp; inTest) :
        mObject(inObject), mTest(inTest) {
        TRACE_BASE
    }
    MyObject mObject;
    std::string mTest;
};

struct ConstValueBase {
    ConstValueBase(const MyObject inObject, const std::string &amp; inTest) :
        mObject(inObject), mTest(inTest) {
        TRACE_BASE
    }
    const MyObject mObject;
    std::string mTest;
};

struct PtrBase {
    PtrBase(MyObject * inObject, const std::string &amp; inTest) :
        mObject(inObject), mTest(inTest) {
        TRACE_BASE
    }
    MyObject * mObject;
    std::string mTest;
};

struct ConstPtrBase {
    ConstPtrBase(const MyObject * inObject, const std::string &amp; inTest) :
        mObject(inObject), mTest(inTest) {
        TRACE_BASE
    }
    const MyObject * mObject;
    std::string mTest;
};

struct RefBase {
    RefBase(MyObject &amp; inObject, const std::string &amp; inTest) :
        mObject(inObject), mTest(inTest) {
        TRACE_BASE
    }
    MyObject &amp; mObject;
    std::string mTest;
};

struct ConstRefBase {
    ConstRefBase(const MyObject &amp; inObject, const std::string &amp; inTest) :
        mObject(inObject), mTest(inTest) {
        TRACE_BASE
    }
    const MyObject &amp; mObject;
    std::string mTest;
};

struct LoadableAndSavableValueBase : public Loadable&lt;Savable&lt;ValueBase&gt; &gt; {
    LoadableAndSavableValueBase(MyObject inObject, const std::string &amp; inTest) :
        Loadable&lt;Savable&lt;ValueBase&gt; &gt;(inObject, inTest) {
        TRACE
    }
};

struct LoadableAndSavableConstValueBase : public Loadable&lt;Savable&lt;ConstValueBase&gt; &gt; {
    LoadableAndSavableConstValueBase(const MyObject inObject, const std::string &amp; inTest) :
        Loadable&lt;Savable&lt;ConstValueBase&gt; &gt;(inObject, inTest) {
        TRACE
    }
};

struct LoadableAndSavablePtrBase : public Loadable&lt;Savable&lt;PtrBase&gt; &gt; {
    LoadableAndSavablePtrBase(MyObject * inObject, const std::string &amp; inTest) :
        Loadable&lt;Savable&lt;PtrBase&gt; &gt;(inObject, inTest) {
        TRACE
    }
};

struct LoadableAndSavableRefBase : public Loadable&lt;Savable&lt;RefBase&gt; &gt; {
    LoadableAndSavableRefBase(MyObject &amp; inObject, const std::string &amp; inTest) :
        Loadable&lt;Savable&lt;RefBase&gt; &gt;(inObject, inTest) {
        TRACE
    }
};

struct LoadableAndSavableConstPtrBase : public Loadable&lt;Savable&lt;ConstPtrBase&gt; &gt; {
    LoadableAndSavableConstPtrBase(const MyObject * inObject, const std::string &amp; inTest) :
        Loadable&lt;Savable&lt;ConstPtrBase&gt; &gt;(inObject, inTest) {
        TRACE
    }
};

struct LoadableAndSavableConstRefBase : public Loadable&lt;Savable&lt;ConstRefBase&gt; &gt; {
    LoadableAndSavableConstRefBase(const MyObject &amp; inObject, const std::string &amp; inTest) :
        Loadable&lt;Savable&lt;ConstRefBase&gt; &gt;(inObject, inTest) {
        TRACE
    }
};

void test() {
    MyObject myObject;
    LoadableAndSavableValueBase valueBase(myObject, "Test");
    LoadableAndSavableConstValueBase constValueBase(myObject, "Test");
    LoadableAndSavablePtrBase ptrBase(&amp;myObject, "Test");
    LoadableAndSavableConstPtrBase constPtrBase(&amp;myObject, "Test");
    LoadableAndSavableRefBase refBase(myObject, "Test");
    LoadableAndSavableConstRefBase constRefBase(myObject, "Test");
}

} // namespace CopyLand

namespace NoCopyLand { // Test with a noncopyable Arg0 object

struct MyObject {
    MyObject() {}

    // noncopyable
    MyObject(const MyObject&amp;);
    const MyObject&amp; operator=(const MyObject&amp;);
};

struct PtrBase {
    PtrBase(MyObject * inObject, const std::string &amp; inTest) :
        mObject(inObject), mTest(inTest) {
        TRACE_BASE
    }
    MyObject * mObject;
    std::string mTest;
};

struct ConstPtrBase {
    ConstPtrBase(const MyObject * inObject, const std::string &amp; inTest) :
        mObject(inObject), mTest(inTest) {
        TRACE_BASE
    }
    const MyObject * mObject;
    std::string mTest;
};

struct RefBase {
    RefBase(MyObject &amp; inObject, const std::string &amp; inTest) :
        mObject(inObject), mTest(inTest) {
        TRACE_BASE
    }
    MyObject &amp; mObject;
    std::string mTest;
};

struct ConstRefBase {
    ConstRefBase(const MyObject &amp; inObject, const std::string &amp; inTest) :
        mObject(inObject), mTest(inTest) {
        TRACE_BASE
    }
    const MyObject &amp; mObject;
    std::string mTest;
};

struct LoadableAndSavablePtrBase : public Loadable&lt;Savable&lt;PtrBase&gt; &gt; {
    LoadableAndSavablePtrBase(MyObject * inObject, const std::string &amp; inTest) :
        Loadable&lt;Savable&lt;PtrBase&gt; &gt;(inObject, inTest)  {
        TRACE
    }
};

struct LoadableAndSavableRefBase : public Loadable&lt;Savable&lt;RefBase&gt; &gt; {
    LoadableAndSavableRefBase(MyObject &amp; inObject, const std::string &amp; inTest) :
        Loadable&lt;Savable&lt;RefBase&gt; &gt;(inObject, inTest)  {
        TRACE
    }
};

struct LoadableAndSavableConstPtrBase : public Loadable&lt;Savable&lt;ConstPtrBase&gt; &gt; {
    LoadableAndSavableConstPtrBase(const MyObject * inObject, const std::string &amp; inTest) :
        Loadable&lt;Savable&lt;ConstPtrBase&gt; &gt;(inObject, inTest)  {
        TRACE
    }
};

struct LoadableAndSavableConstRefBase : public Loadable&lt;Savable&lt;ConstRefBase&gt; &gt; {
    LoadableAndSavableConstRefBase(const MyObject &amp; inObject, const std::string &amp; inTest) :
        Loadable&lt;Savable&lt;ConstRefBase&gt; &gt;(inObject, inTest)  {
        TRACE
    }
};

// Also include a test with std::type_info.
struct TypeInfo {
    TypeInfo(const std::type_info &amp; inTypeInfo) : mTypeInfo(inTypeInfo) {}

    const std::type_info &amp; mTypeInfo;
};

struct LoadableAndSavableTypeInfo : public Loadable&lt;Savable&lt;TypeInfo&gt; &gt; {
    LoadableAndSavableTypeInfo() : Loadable&lt;Savable&lt;TypeInfo&gt; &gt;(typeid(this)) {}
};

void test() {
    MyObject myObject;
    LoadableAndSavablePtrBase ptrBase(&amp;myObject, "Test");
    LoadableAndSavableConstPtrBase constPtrBase(&amp;myObject, "Test");
    LoadableAndSavableRefBase refBase(myObject, "Test");
    LoadableAndSavableConstRefBase constRefBase(myObject, "Test");
    LoadableAndSavableTypeInfo typeInfo;
    typeInfo.mTypeInfo.name(); // get the std::type_info
}

} // namespace NoCopyLand

int main() {
    CopyLand::test();
    NoCopyLand::test();
    return 0;
}
</code></pre>

<p>When running the program it produces the following output:</p>

<pre><code>g++ -o test main.cpp

CopyLand::ValueBase::ValueBase(CopyLand::MyObject, const std::string&amp;)
Savable&lt;BaseType&gt;::Savable(Arg0&amp;, Arg1&amp;) [with Arg0 = CopyLand::MyObject, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = CopyLand::ValueBase]
Loadable&lt;BaseType&gt;::Loadable(Arg0&amp;, Arg1&amp;) [with Arg0 = CopyLand::MyObject, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = Savable&lt;CopyLand::ValueBase&gt;]
CopyLand::LoadableAndSavableValueBase::LoadableAndSavableValueBase(CopyLand::MyObject, const std::string&amp;)

CopyLand::ConstValueBase::ConstValueBase(CopyLand::MyObject, const std::string&amp;)
Savable&lt;BaseType&gt;::Savable(Arg0&amp;, Arg1&amp;) [with Arg0 = const CopyLand::MyObject, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = CopyLand::ConstValueBase]
Loadable&lt;BaseType&gt;::Loadable(Arg0&amp;, Arg1&amp;) [with Arg0 = const CopyLand::MyObject, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = Savable&lt;CopyLand::ConstValueBase&gt;]
CopyLand::LoadableAndSavableConstValueBase::LoadableAndSavableConstValueBase(CopyLand::MyObject, const std::string&amp;)

CopyLand::PtrBase::PtrBase(CopyLand::MyObject*, const std::string&amp;)
Savable&lt;BaseType&gt;::Savable(Arg0&amp;, Arg1&amp;) [with Arg0 = CopyLand::MyObject*, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = CopyLand::PtrBase]
Loadable&lt;BaseType&gt;::Loadable(Arg0&amp;, Arg1&amp;) [with Arg0 = CopyLand::MyObject*, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = Savable&lt;CopyLand::PtrBase&gt;]
CopyLand::LoadableAndSavablePtrBase::LoadableAndSavablePtrBase(CopyLand::MyObject*, const std::string&amp;)

CopyLand::ConstPtrBase::ConstPtrBase(const CopyLand::MyObject*, const std::string&amp;)
Savable&lt;BaseType&gt;::Savable(Arg0&amp;, Arg1&amp;) [with Arg0 = const CopyLand::MyObject*, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = CopyLand::ConstPtrBase]
Loadable&lt;BaseType&gt;::Loadable(Arg0&amp;, Arg1&amp;) [with Arg0 = const CopyLand::MyObject*, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = Savable&lt;CopyLand::ConstPtrBase&gt;]
CopyLand::LoadableAndSavableConstPtrBase::LoadableAndSavableConstPtrBase(const CopyLand::MyObject*, const std::string&amp;)

CopyLand::RefBase::RefBase(CopyLand::MyObject&amp;, const std::string&amp;)
Savable&lt;BaseType&gt;::Savable(Arg0&amp;, Arg1&amp;) [with Arg0 = CopyLand::MyObject, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = CopyLand::RefBase]
Loadable&lt;BaseType&gt;::Loadable(Arg0&amp;, Arg1&amp;) [with Arg0 = CopyLand::MyObject, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = Savable&lt;CopyLand::RefBase&gt;]
CopyLand::LoadableAndSavableRefBase::LoadableAndSavableRefBase(CopyLand::MyObject&amp;, const std::string&amp;)

CopyLand::ConstRefBase::ConstRefBase(const CopyLand::MyObject&amp;, const std::string&amp;)
Savable&lt;BaseType&gt;::Savable(Arg0&amp;, Arg1&amp;) [with Arg0 = const CopyLand::MyObject, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = CopyLand::ConstRefBase]
Loadable&lt;BaseType&gt;::Loadable(Arg0&amp;, Arg1&amp;) [with Arg0 = const CopyLand::MyObject, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = Savable&lt;CopyLand::ConstRefBase&gt;]
CopyLand::LoadableAndSavableConstRefBase::LoadableAndSavableConstRefBase(const CopyLand::MyObject&amp;, const std::string&amp;)

NoCopyLand::PtrBase::PtrBase(NoCopyLand::MyObject*, const std::string&amp;)
Savable&lt;BaseType&gt;::Savable(Arg0&amp;, Arg1&amp;) [with Arg0 = NoCopyLand::MyObject*, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = NoCopyLand::PtrBase]
Loadable&lt;BaseType&gt;::Loadable(Arg0&amp;, Arg1&amp;) [with Arg0 = NoCopyLand::MyObject*, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = Savable&lt;NoCopyLand::PtrBase&gt;]
NoCopyLand::LoadableAndSavablePtrBase::LoadableAndSavablePtrBase(NoCopyLand::MyObject*, const std::string&amp;)

NoCopyLand::ConstPtrBase::ConstPtrBase(const NoCopyLand::MyObject*, const std::string&amp;)
Savable&lt;BaseType&gt;::Savable(Arg0&amp;, Arg1&amp;) [with Arg0 = const NoCopyLand::MyObject*, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = NoCopyLand::ConstPtrBase]
Loadable&lt;BaseType&gt;::Loadable(Arg0&amp;, Arg1&amp;) [with Arg0 = const NoCopyLand::MyObject*, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = Savable&lt;NoCopyLand::ConstPtrBase&gt;]
NoCopyLand::LoadableAndSavableConstPtrBase::LoadableAndSavableConstPtrBase(const NoCopyLand::MyObject*, const std::string&amp;)

NoCopyLand::RefBase::RefBase(NoCopyLand::MyObject&amp;, const std::string&amp;)
Savable&lt;BaseType&gt;::Savable(Arg0&amp;, Arg1&amp;) [with Arg0 = NoCopyLand::MyObject, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = NoCopyLand::RefBase]
Loadable&lt;BaseType&gt;::Loadable(Arg0&amp;, Arg1&amp;) [with Arg0 = NoCopyLand::MyObject, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = Savable&lt;NoCopyLand::RefBase&gt;]
NoCopyLand::LoadableAndSavableRefBase::LoadableAndSavableRefBase(NoCopyLand::MyObject&amp;, const std::string&amp;)

NoCopyLand::ConstRefBase::ConstRefBase(const NoCopyLand::MyObject&amp;, const std::string&amp;)
Savable&lt;BaseType&gt;::Savable(Arg0&amp;, Arg1&amp;) [with Arg0 = const NoCopyLand::MyObject, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = NoCopyLand::ConstRefBase]
Loadable&lt;BaseType&gt;::Loadable(Arg0&amp;, Arg1&amp;) [with Arg0 = const NoCopyLand::MyObject, Arg1 = const std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;, BaseType = Savable&lt;NoCopyLand::ConstRefBase&gt;]
NoCopyLand::LoadableAndSavableConstRefBase::LoadableAndSavableConstRefBase(const NoCopyLand::MyObject&amp;, const std::string&amp;)
Savable&lt;BaseType&gt;::Savable(Arg0&amp;) [with Arg0 = const std::type_info, BaseType = NoCopyLand::TypeInfo]
Loadable&lt;BaseType&gt;::Loadable(Arg0&amp;) [with Arg0 = const std::type_info, BaseType = Savable&lt;NoCopyLand::TypeInfo&gt;]
</code></pre>

<p>Please let me know if there is anything wrong in my example or in my conclusion :)</p>
