How do I prevent diamond pattern in nested template types using static assert and type traits? [duplicate]

StackOverflow https://stackoverflow.com/questions/8852245

Question

Possible Duplicate:
Is there a way to prevent a class from being derived from twice using a static assert and type trait?

What I'd like to prevent is more than one of the C based template from being derived in D (i.e. there should only ever be one instance of C derived from). Was hoping for maybe a static assert in C or B that may solve this.

// My Classes
template <class T>
class A {};

class B {};

template <class T, class S>
class C : public B, public virtual A<T> {};

// Someone elses code using my classes
class D : public C<Type1, Type2>, public C<Type3, Type4>
{
};
Was it helpful?

Solution

As it stands, it's impossible for B or C to detect what else a more derived class inherits from, so you can't add an assertion there. However, by adding a "curiously recursive" template parameter, you can tell C what the derived class is. Unfortunately, this does require the derived class to give the correct template argument, and there's no way to enforce that.

You can then determine whether the derived class inherits from B in more than one way; it is a base class, but you can't convert a derived class pointer to B* (since that conversion is ambiguous). Note that this doesn't necessarily indicate multiple inheritance; the test will also fail if there's non-public inheritance.

So the best solution I can think of is:

#include <type_traits>

template <class T> class A {};
class B {};

template <class T, class S, class D>
class C : public B, public virtual A<T> {
public:
    C() {
        static_assert(
            std::is_base_of<C,D>::value && std::is_convertible<D*,B*>::value, 
            "Multiple inheritance of C");
    }
};

struct Type1 {};
struct Type2 {};
struct Type3 {};
struct Type4 {};

class Good : public C<Type1, Type2, Good> {};
class Evil : public C<Type1, Type2, Evil>, public C<Type3, Type4, Evil> {};

int main()
{
    Good good;
    Evil evil; // Causes assertion failure
}

I had to put the assertion in the constructor rather than the class definition, since some of the types are incomplete when the class template is instantiated. Unfortunately, this means that the error will only be reported for classes that are actually instantiated.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top