【问题标题】:How to implement the CRTP following MISRA C++如何在 MISRA C++ 之后实现 CRTP
【发布时间】:2018-10-11 08:42:22
【问题描述】:

我的团队正在开发一个嵌入式系统,我们需要遵循 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 Rule 5-2-7 violation: An object with pointer type shall not be converted to an unrelated pointer type, either directly or indirectly 我在 CRTP 中有同样的错误。

编辑:仅提到 C++03,没有像 boost 这样的外部库。

【问题讨论】:

    标签: c++ c++03 crtp static-cast misra


    【解决方案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;
    

    【讨论】:

    • 谢谢。那行得通。因此,如果有人遇到同样的问题,为了完整起见:如果 T 没有虚拟方法,则使用私有继承,否则 MISRA 也会抱怨。
    【解决方案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 并在铸造make seance 时使操作符可用:

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

    或者两者都用。

    试试这个我希望工具能理解并停止报告错误。如果不是,那么恕我直言,这是工具中的错误。

    有人指出必须使用C++03。在这种情况下,您可以使用boost,此帮助程序在最初定义的位置模板enable_ifis_base_of

    【讨论】:

    • 看起来不太C++03
    • @jakub_d:如果您只是将 std::is_base_of 的实现复制到某处的代码中,sfinae 解决方案也适用于 c++03。 std::is_base_of 与 c++11/14 核心语言无关,它只是一个可以复制的库添加。也可以简单地使用模板专业化在 c++03 上构建 static_assert。
    • 这里的问题是,当类被实例化时,类作用域中的static_assertion 将被检查=>class B : public UpdateMethod&lt;B&gt; => B 在这里不完整,因此检查将失败。
    • @jakub_d 这个限制没有被描述。这是我错过的评论。问题应该得到纠正,我的回答也是。无论如何,SFINAE 在 C++03 中工作,但需要额外的工作。
    • @StoryTeller:检查方法范围效果很好。所以应该修改答案;)
    【解决方案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 {}
    };
    

    【讨论】:

    • fyi:这可以工作,但是你有另一个 MISRA 错误:基类没有非析构函数虚函数,这意味着你应该继承私有,然后你不能访问更新。但很好的尝试。
    • 你也必须实现复制/移动构造函数。
    猜你喜欢
    • 2021-10-30
    • 2023-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多