Как предотвратить паттерн алмаза в вложенных типах шаблонов, используя статические аспекты и признаки типа? [дублировать

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

Вопрос

Возможный дубликат:
Есть ли способ предотвратить получение класса в два раза с использованием статического утверждения и черты типа?

То, что я хотел бы предотвратить, - это более чем один из шаблонов, основанных на C, был получен в D (то есть когда -либо должен быть только один экземпляр, полученный C). Надеялся, что, возможно, статическое утверждение в C или B, которое может решить это.

// 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>
{
};
Это было полезно?

Решение

В качестве стоят, это невозможно для B или же C Чтобы обнаружить, от чего еще более полученные классы наследуют, так что вы не можете добавить там утверждение. Однако, добавив «любопытно рекурсивный» параметр шаблона, вы можете сказать C что такое полученный класс. К сожалению, это требует от полученного класса, чтобы дать правильный аргумент шаблона, и нет никакого способа обеспечить соблюдение этого.

Затем вы можете определить, наследует полученный класс от B более чем одним способом; Это является базовый класс, но вы не мочь преобразовать полученный указатель класса в B* (Поскольку это преобразование неоднозначно). Обратите внимание, что это не обязательно указывает на множественное наследство; Тест также потерпит неудачу, если будет непубличное наследство.

Итак, лучшее решение, о котором я могу придумать:

#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
}

Мне пришлось поместить утверждение в конструктор, а не определение класса, поскольку некоторые типы являются неполными, когда шаблон класса создается. К сожалению, это означает, что ошибка будет сообщена только для классов, которые фактически создаются.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top