Как реализовать CRTP, следуя MISRA C ++ - PullRequest
0 голосов
/ 11 октября 2018

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

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

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

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

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.

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

Ответы [ 3 ]

0 голосов
/ 11 октября 2018

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

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;
0 голосов
/ 12 октября 2018

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

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 {}
};
0 голосов
/ 11 октября 2018

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

Должен быть какой-то способ помочь инструменту понять ситуацию.Наилучшим способом были бы 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();
    }
};

Или использовать оба.

ПопробуйтеЯ надеюсь, что этот инструмент поймет это и перестанет сообщать об ошибке.Если нет, то, IMHO, это ошибка в инструменте.

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

...