Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Verify template type

Sorry for my poor english I'll try to do my best.

I want to design an interface that should be used like this:

class MyObject : public IMyInterface<MyObject>
{
    // ...
};

The interface could look like this:

template <class _TMyObject>
class IMyInterface
{
    virtual _TMyObject* Get() = 0;
};

What i'm looking after, is a way to verify, at compile time, that the interface is used as intended. How can I test if _TMyObject "is-a" IMyInterface<_TMyObject>? Inside the interface definition, with a static_assert for example.

Thanks for any help :). Have a nice day!

like image 950
diccy Avatar asked Jan 02 '23 21:01

diccy


2 Answers

You can't put static_assert inside the class itself, because D is an incomplete type, but you can put it in the destructor (or constructor, but there can be many constructors):

template<class D>
struct B
{
    ~B()
    {
        static_assert(std::is_base_of_v<B, D>);
    };
};

struct Not_E {};

struct D : B<D> { };         
struct E : B<Not_E> { };     

void foo()
{
     D d;     // OK
     E e;     // Fails
}

Addition. Note that this solution is not a complete protection against incorrect usage of CRTP. Please refer to Some Programmer Dude's answer for a nice example of error that can't be caught by it.

like image 57
Evg Avatar answered Jan 11 '23 23:01

Evg


Since C++11 there are many type property traits that could be used to do checks at compile-time.

For example std::is_base_of which in your case could be used like perhaps

template<typename TChild>
struct IMyInterface
{
    static_assert(std::is_base_of<IMyInterface, TChild>::value, "Derived class not derived from IMyInterface");

    // ...
};

Note: The exact code shown above will not work directly, but rather show the principle.

Of course, that do allow something like

class MyFirstClass : public IMyInterface<MyFirstClass>
{
    // ...
};

//                        Note wrong class in template
//                                        vvvvvvvvvvvv
class MySecondClass : public IMyInterface<MyFirstClass>
{
    // ...
};

So to answer your question if it's possible for such a check: Not really the way you want. Even using other traits and meta-programming, you can never guarantee that the template argument for the interface class is "correct" when used in the CRTP.

The only way I can see it work is by using down-casting at run-time with dynamic_cast, something like dynamic_cast<TChild*>(this) != nullptr in the interface class.

like image 25
Some programmer dude Avatar answered Jan 11 '23 23:01

Some programmer dude