如何在MISRA C++之后实施CRTP

How to implement the CRTP following MISRA C++

本文关键字:CRTP 之后 C++ MISRA      更新时间:2023-10-16

我的团队正在开发一个嵌入式系统,我们需要遵循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这样的外部库。

您可以使用相反的方法:

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;

好的问题是该工具检查模板定义而不是模板实例化。

必须有某种方法可以帮助工具了解情况。最好的方法是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();
}
};

或者两者兼而有之。

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

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

检查器不喜欢的是向下投射。我们可以完全不选角吗?派生类可以使用正确的类型提供正确的值,例如在构造期间。有点预落。它将花费您一个额外的存储指针。喜欢这个:

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 {}
};