如果基类是可能的T
知道其派生类的类型。这些知识可以通过 CRTP 或通过重载标签传递给其构造函数。这是后一种情况:
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." );
Then, T::T( Derived * )
如果它有两个专业化(具有不同的专业化),则需要做一些会导致问题的事情Derived
)。友元函数对此非常有用。实例化一个辅助的非成员类,具体取决于<T, Derived>
,有一个friend
函数取决于T
但不是Derived
.
T_Derived_reservation< T, Derived >{};
}
};
这是辅助类。 (它的定义应该出现在T
.) 首先,它需要一个基类来允许 ADLT_Derived_reservation< T, Derived >
找到一个没有提到的签名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
文件声明不同的不兼容的派生类,但我无法阻止链接器合并内联函数。所以assert
将会开火。 (您可能可以设法在标头中声明所有派生类,而不必担心assert
开火。)
Demo http://coliru.stacked-crooked.com/a/045e8d56da5cc6f5.
你已经编辑说T
无法知道其派生类型。嗯,在编译时您无能为力,因为该信息根本不可用。如果T
是多态的,那么你可以观察到动态类型是派生类A
or B
,但不在构造函数或析构函数中。如果派生类可靠地调用了其他一些函数,您可以挂钩:
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.
}
};