如何防止模板类多次派生? [英] How to prevent a template class from being derived more than once?
问题描述
我有以下模板类:
template<class I>
class T : public I
{
// ...
};
对于给定的模板参数<$ c,此模板类需要派生一次(且仅一次) $ c>我。
class A : public T<U> {}; // ok
class B : public T<V> {}; // ok
class C : public T<U> {}; // compile error
模板类 T
可以适应这种行为(当班级 A
, B
, U
, V
不能);但是, T
必须不了解派生类 A
, B
, C
。
Template class T
can be adapted to achieve such a behavior (while classes A
, B
, U
, V
cannot); however, T
must not have any knowledge about derived classes A
, B
, C
.
有没有办法防止这样的模板类被多次派生?理想情况下,在这种情况下发出编译错误,或者至少是链接器错误。
Is there any way to prevent such a template class from being derived more than once? Ideally issuing a compilation error in such a case or, at least, a linker error.
推荐答案
如果是基类,这是可能的 T
知道其派生类的类型。这些知识可以通过CRTP或重载标记传递给它的构造函数。以下是后一种情况:
This is possible if the base class T
knows the types of its derived classes. This knowledge can be passed by CRTP or by an overloading tag to its constructor. Here's the latter case:
template<class I>
class T : public I
{
protected:
template< class Derived >
T( Derived * ) {
static_assert ( std::is_base_of< T, Derived >::value,
"Be honest and pass the derived this to T::T." );
然后, T :: T(派生*)
如果它有两个特化(具有不同的 Derived
),则需要做一些会导致问题的事情。朋友的功能非常棒。根据< T,Derived>
实例化辅助非成员类,并依赖于朋友
函数 T
但不是派生
。
Then, T::T( Derived * )
needs to do something that will cause a problem if it has two specializations (with different Derived
). Friend functions are great for that. Instantiate an auxiliary, non-member class depending on <T, Derived>
, with a friend
function that depends on T
but not Derived
.
T_Derived_reservation< T, Derived >{};
}
};
这是辅助类。 (它的定义应该在 T
之前。)首先,它需要一个基类来允许上的ADL T_Derived_reservation< T,Derived>
查找未提及 Derived
的签名。
Here's the auxiliary class. (Its definition should come before T
.) First, it needs a base class to allow ADL on T_Derived_reservation< T, Derived >
to find a signature that doesn't mention Derived
.
template< typename T >
class T_reservation {
protected:
// Make the friend visible to the derived class by ADL.
friend void reserve_compile_time( T_reservation );
// Double-check at runtime to catch conflicts between TUs.
void reserve_runtime( std::type_info const & derived ) {
#ifndef NDEBUG
static std::type_info const & proper_derived = derived;
assert ( derived == proper_derived &&
"Illegal inheritance from T." );
#endif
}
};
template< typename T, typename Derived >
struct T_Derived_reservation
: T_reservation< T > {
T_Derived_reservation() {
reserve_compile_time( * this );
this->reserve_runtime( typeid( Derived ) );
}
/* Conflicting derived classes within the translation unit
will cause a multiple-definition error on reserve_compile_time. */
friend void reserve_compile_time( T_reservation< T > ) {}
};
当两个 .cpp >时出现链接错误会很好code> files声明了不同的不兼容派生类,但我无法阻止链接器合并内联函数。因此,
断言
将触发。 (您可以设法在标头中声明所有派生类,而不用担心断言
触发。)
It would be nice to get a link error when two .cpp
files declare different incompatible derived classes, but I can't prevent the linker from merging the inline functions. So, the assert
will fire instead. (You can probably manage to declare all the derived classes in a header, and not worry about the assert
firing.)
演示。
您已编辑过说 T
无法知道其派生类型。好吧,在编译时你无能为力,因为这些信息根本不可用。如果 T
是多态的,那么您可以将动态类型视为派生类 A
或 B
,但不在构造函数或析构函数中。如果派生类可靠地调用了其他一些函数,你可以挂钩:
You've edited to say that T
cannot know its derived types. Well, there's nothing you can do at compile time, since that information is simply unavailable. If T
is polymorphic, then you can observe the dynamic type to be the derived class A
or B
, but not in the constructor or destructor. If there's some other function reliably called by the derived class, you can hook into that:
template< typename I >
class T {
protected:
virtual ~ T() = default;
something_essential() {
#ifndef NDEBUG
static auto const & derived_type = typeid( * this );
assert ( derived_type == typeid( * this ) &&
"Illegal inheritance from T." );
#endif
// Do actual essential work.
}
};
这篇关于如何防止模板类多次派生?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!