当前位置:  开发笔记 > 编程语言 > 正文

如何防止模板类被多次派生?

如何解决《如何防止模板类被多次派生?》经验,为你挑选了2个好方法。

我有以下模板类:

template
class T : public I
{
    // ...
};

对于给定的模板参数,此模板类需要一次(且仅一次)派生I.

class A : public T  {};    // ok
class B : public T  {};    // ok
class C : public T  {};    // compile error

模板类T可以适合于实现这样的行为(而类A,B,U,V不能); 但是,T决不能有关于派生类的任何知识A,B,C.

有没有办法防止这样的模板类被多次派生?理想情况下,在这种情况下发出编译错误,或者至少是链接器错误.



1> Potatoswatte..:

如果基类T知道其派生类的类型,则可以这样做.这些知识可以通过CRTP或重载标记传递给它的构造函数.这是后一种情况:

template
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 * )如果它有两个特化(具有不同的特征Derived),则需要做一些会导致问题的事情.朋友的功能非常棒.根据具有friend依赖T但不依赖的函数来实例化辅助非成员类Derived.

        T_Derived_reservation< T, Derived >{};
    }
};

这是辅助类.(它的定义应该在之前T.)首先,它需要一个基类来允许ADL T_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触发.)

演示.


您已编辑过说T无法知道其派生类型.好吧,在编译时你无能为力,因为这些信息根本不可用.如果T是多态的,那么你可以观察动态类型是派生类AB构造函数和析构函数,但不是.如果派生类可靠地调用了其他一些函数,您可以将其挂钩:

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.
    }
};



2> W.F...:

我不是宏的忠实粉丝,但如果使用宏对你来说不是问题 - 你可以使用一个简单紧凑的解决方案,如下所示:

#include 

template 
struct prohibit_double_inheritance { };

#define INHERIT(DERIVING, BASE) \
    template<> struct prohibit_double_inheritance { };\
    struct DERIVING: BASE


template
struct T: I
{
    // ...
    static void do_something() {
        std::cout << "hurray hurray!" << std::endl;
    }
};

struct U { };
struct V { };

INHERIT(A, T) {
};

//INHERIT(B, T) { // cause redetinition of the struct 
//};                 // prohibit_double_inheritance> 

int main() {
    A::do_something();
}

[现场演示]

推荐阅读
mobiledu2402851377
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有