C ++ Проверить тип шаблона - PullRequest
       10

C ++ Проверить тип шаблона

0 голосов
/ 09 сентября 2018

Извините за мой плохой английский. Я постараюсь сделать все возможное.

Я хочу разработать интерфейс, который должен использоваться следующим образом:

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

Интерфейс может выглядеть так:

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

То, что я наблюдаю, это способ проверить, во время компиляции, что интерфейс используется по назначению. Как я могу проверить, если _TMyObject "is-a" IMyInterface<_TMyObject>? Внутри определения интерфейса, например, static_assert.

Спасибо за любую помощь :). Хорошего дня!

Ответы [ 2 ]

0 голосов
/ 09 сентября 2018

Начиная с C ++ 11 существует много признаков свойства типа , которые можно использовать для проверки во время компиляции.

Например std::is_base_of, который в вашем случае может быть использован как, возможно,

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

    // ...
};

Примечание. Точный код, показанный выше, не будет работать напрямую, а скорее покажет принцип.

Конечно, это позволяет что-то вроде

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

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

Итак, чтобы ответить на ваш вопрос, если это возможно для такой проверки: не совсем так, как вы хотите. Даже используя другие черты и метапрограммирование, вы никогда не сможете гарантировать, что аргумент шаблона для класса интерфейса является «правильным» при использовании в CRTP .

Единственный способ увидеть, как это работает, - использовать принижение во время выполнения с dynamic_cast, что-то вроде dynamic_cast<TChild*>(this) != nullptr в классе интерфейса.

0 голосов
/ 09 сентября 2018

Вы не можете поместить static_assert внутри самого класса, потому что D является неполным типом, но вы можете поместить его в деструктор (или конструктор, но может быть много конструкторов):

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
}

Добавление. Обратите внимание, что это решение не является полной защитой от неправильного использования CRTP. Пожалуйста, обратитесь к ответу Some Programmer Dude для хорошего примера ошибки, которая не может быть поймана им.

...