Как реализовать CRTP после MISRA С++

Моя команда разрабатывает встроенную систему, где нам нужно следовать MISRA C++.

Мы реорганизуем код, чтобы использовать меньше виртуальных методов, поэтому мы пытаемся реализовать CRTP для использования статического полиморфизма вместо динамического.

Но у нас есть проблема, что статический полиморфизм требует преобразования указателя, поэтому наш статический анализатор проверки жалуется.

Вот интерфейс

template <typename T>
class UpdateMethod
{
protected:
    ~UpdateMethod() {}
 public:
    void operator()() const
    {
        // [MISRA Rule 5-2-7] violation:
        static_cast<const T*>(this)->update();
    }
};

Вот одна из реализаций:

class A
    : public UpdateMethod<A>
{
 public:
    void update() const {}
};

Когда проходит контролер MISRA, он жалуется на static_cast (преобразование из ptr в ptr (e926).

Итак, мой вопрос: есть ли хороший способ реализовать CRTP без необходимости пресекать предупреждение MISRA, поэтому безопасным способом?

Связанный с этим вопрос только о преобразовании указателя: MISRA C++ 2008 Правило 5-2-7 Нарушение: объект с типом указателя не должен быть преобразован в несвязанный тип указателя, прямо или косвенно у меня такая же ошибка в CRTP.

Изменение: как упоминалось только C++ 03, и никакой внешней библиотеки, такой как boost.

Ответы

Ответ 1

Вы можете использовать обратный подход:

template <typename T>
class UpdateMethod : public T
{
 public:
    void operator()() const
    {
        this->update();
    }
};

class A_impl
{
 public:
    void update() const {}
};

typedef UpdateMethod<A_impl> A;

Ответ 2

Проблема в том, что инструмент проверяет определение шаблона, а не на создание экземпляра шаблона.

Должен быть какой-то способ помочь инструменту понять ситуацию. Лучший способ - это концепции C++2a, но, скорее всего, инструмент не поддерживает это, и компилятор, вероятно, тоже этого не делает.

Другим решением будет предоставление static_assert, надеясь, что инструмент поймет, что:

template <typename T>
class UpdateMethod
{
    static_assert(std::is_base_of<UpdateMethod<T>, T>::value, "This is CRTP");
protected:
    ~UpdateMethod() {}
 public:
    void operator()() const
    {
        static_cast<const T*>(this)->update();
    }
};

Другой способ - использовать SFINAE и сделать оператор доступным при кастинге:

template <typename T>
class UpdateMethod
{
protected:
    ~UpdateMethod() {}
public:

    typename std::enable_if<std::is_base_of<UpdateMethod<T>, T>::value>::type
    operator()() const
    {
        static_cast<const T*>(this)->update();
    }
};

Или используйте оба.

Попробуйте это, я надеюсь, что инструмент поймет это и перестанет сообщать об ошибке. Если нет, то ИМХО это ошибка в инструменте.

Кто-то указывает, что С++ 03 должен использоваться. В этом случае вы можете использовать boost, где это вспомогательные шаблоны enable_if и is_base_of, где изначально определено.

Ответ 3

То, что проверяет не нравится, - это понижение. Можем ли мы это сделать без кастинга вообще? Производный класс может предоставить правильное значение с правильным типом, например, во время строительства. Тип предварительного понижения. Это будет стоить вам лишнего хранимого указателя. Как это:

template <typename T>
class UpdateMethod
{
protected:
    T* implThis;
    ~UpdateMethod() {}
    UpdateMethod(T* implThis):implThis(implThis) {}
 public:
    void operator()() const
    {
        // this was the problematic cast
        implThis->update();
    }
};

class A
    : public UpdateMethod<A>
{
 public:
    A(): UpdateMethod(this) {}
    void update() const {}
};