How to prevent a template class from being derived more than once?

shrike

I have the following template class:

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

This template class need to be derived once (and only once) for a given template parameter I.

class A : public T<U>  {};    // ok
class B : public T<V>  {};    // ok
class C : public T<U>  {};    // compile error

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.

Potatoswatter

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." );

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

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 > ) {}
};

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.)

Demo.


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

Este artículo se recopila de Internet, indique la fuente cuando se vuelva a imprimir.

En caso de infracción, por favor [email protected] Eliminar

Editado en
0

Déjame decir algunas palabras

0Comentarios
Iniciar sesiónRevisión de participación posterior

Artículos relacionados

template class derived from `const` specialized version

How to conditionally instantiate a template class which has more than one template parameter?

How to keep strings that are repeated more than once?

How to prevent a class from being inherited outside the library, while being inherited by public classes?

How to derived from the Effect class

How to prevent static methods being accessed by multiple Servlet Threads at once

remove all elements that occur more than once from array

How to prevent a UIViewController from being popped out?

How to add more than once node per zone in elastic cloud

How do I stop more than 1 bullet firing at once?

How to use more than once the stdin with a "-" (dash) in a bash script?

Conditional override in derived class template

Visibility of a base class constructor in a derived template class

Android: How to prevent image from being scaled in ImageView or ImageButton?

How can one prevent a program from being opened with Python?

How can I prevent a matTooltip text from being truncated?

How to prevent an optional field from being validated in codeigniter 3.1.11

The probability of a variable occurring more than once in a dataset

Removing duplicates that appear more than once

Cannot set Content More than once xaml

CLIPS Rules trigger more than once

Getting NaN from JavaScript function trying to get same data more than once

Curious on how to target more than one class with same function

How to obtain the derived class type from base when calling a method

How to get the name of a derived class from a vector of base classes

How to derive a class that is already derived from Halide::Generator?

overriding the template base method in derived class?

How to fix R6031 - Attempt to initialize the CRT more than once. This indicates a bug in your application?

In MySQL database how can I create a different key for a field that repeats more than once in a row by php and json

TOP Lista

CalienteEtiquetas

Archivo