问题描述
在实时计算中,有时会有速率组的概念。这本质上是调用给定函数的频率。 (例如,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>()
内部调用某个其他模板化函数将自动使用正确的费率组)。
编辑:这是对一些理想属性的更详细的描述。
- 可能最大的特点是设计时编译器警告。假设特定函数
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 的基础上,模板将具有速率组的排序,以禁止使用比自身速率组慢的函数:
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
或模板。