Как предотвратить паттерн алмаза в вложенных типах шаблонов, используя статические аспекты и признаки типа? [дублировать
-
28-10-2019 - |
Вопрос
Возможный дубликат:
Есть ли способ предотвратить получение класса в два раза с использованием статического утверждения и черты типа?
То, что я хотел бы предотвратить, - это более чем один из шаблонов, основанных на 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
}
Мне пришлось поместить утверждение в конструктор, а не определение класса, поскольку некоторые типы являются неполными, когда шаблон класса создается. К сожалению, это означает, что ошибка будет сообщена только для классов, которые фактически создаются.