是否有 C++ 习惯用法通过模板魔术将所谓的速率组实时计算编码为函数?

问题描述

在实时计算中,有时会有速率组的概念。这本质上是调用给定函数的频率。 (例如,RG 10 可能意味着每 10 毫秒执行一次)。

我想知道 C++ 中是否有一种很好的方法可以通过模板魔术来编码此属性,如下所示:

template<int rate_group> void integrate( float& some_integral,float spot_value );

上述函数可以实例化如下:

while(true) // outer control loop
{
     // do something
     integrate<10>( error_sum,sense_Feedback );
     
     for( int i = 0 ; i < 10 ; i++) // inner control loop
     {
          integrate<1>( error_sum_2,some_other_sense );

          // sleep 1ms
     }
}

以上是一个玩具场景,我只是在探索是否有现有的习语来做这种事情。我认为我想从这样的模板化方法中获得的最重要的属性属性传递性:具有 rategroup rate_group 的任何函数都会自动(在编译时)解析为它调用的正确专用子例程. (例如,从 integrate<10>() 内部调用某个其他模板化函数自动使用正确的费率组)。


编辑:这是对一些理想属性的更详细的描述。

  1. 可能最大的特点是设计时编译器警告。假设特定函数 foo 不允许在快速组中,我想确保我调用的任何顶级函数树都不会调用 foo<10>,但允许调用 foo<100>。上面确实需要有一种机制来根据上下文实例化模板。例如。带有 template<int rate_group>函数自动实例化它使用速率组调用的任何函数

示例:

template<int rate_group> void foo( /* ... */ );
template<int rate_group> void bar( /* ... */ );
template<int rate_group> void baz( /* ... */ );

/* impl */
void foo<10>( /* ... */ ){ std::static_assert(false,"this method cannot be called at this rate group"); };

template<int rate_group> void bar( /* ... */ )
{
    // do stuff
    foo();
}

使用 bar<100> 应该可以正常工作,但尝试构建 bar<10> 应该会导致编译时断言。

上述功能发挥作用的关键是能够为任何 C++ 块提供上下文速率组属性,并且将其传递给该块内进行的任何调用

  1. 在#1 的基础上,模板将具有速率组的排序,以禁止使用比自身速率组慢的函数

    void foo<50>( /* ... */ )
    {
        bar<10>();  // OK - this is a higher rate group,and would be allowed
        bar<50>();  // OK - same rate-group
        bar<100>(); // NO - this Could be a slow function - fail compilation
    }
    

仅这两个功能就已经有很长的路要走。但是,两者都取决于属性自动维护。我不确定 C++ 是否允许这种级别的元编码。

解决方法

我不知道您的问题的习语,但您确实可以使用模板来处理。

根据您的限制:

  • 内部函数不应调用更大的速率。
  • 在给定范围内限制功能的可能性

我会选择模板类

template <std::size_t N>
class RateGroup
{
    friend int main(int,char**); // Give only one entry point
                                  // to create main rates.
 
    Rate() = default;
public:
    Rate(const& Rate) = default;

    template <std::size_t N2>
    RateGroup<N2> New() const requires (N2 <= N) { return {}; }
    // Or SFINAE or static_assert instead of C++20 requires.
};

那么你的功能可能是

template<std::size_t N>
void foo(RateGroup<N> /* ... */ ) requires (N > 10);
template<std::size_t N> void bar(RateGroup<N> rateGroup,/* ... */ )
{
    // ...
    foo(rateGroup /*,...*/);
}

inline void baz(RateGroup<50> rateGroup /*,... */ )
{
    bar(rateGroup); // Same one,so 50.
    bar(rateGroup.New<10>());  // OK,10 < 50.
    bar(rateGroup.New<100>()); // Fail to compile as expected,!(100 < 50).
    bar(RateGroup<100>()); // Fail to compile: constructor is restricted to allowed functions

}

您可以为您的函数设置固定的 RateGroup 或模板。