In realtime computing, there is sometimes a concept of a rate-group. This is essentially the frequency at which a given function will be called. (e.g. RG 10 might imply executing every 10ms).
I'm wondering if there's a nice way in C++ to encode this property via template magic like so:
template<int rate_group> void integrate( float& some_integral, float spot_value );
The above function could be instantiated as follows:
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
}
}
The above is a toy scenario and I'm simply exploring if there's an existing idiom to do this kind of thing. I think the most important property I'd like to get from a templated approach like this is property transitivity: any function with a rategroup rate_group would automatically (at compile time) resolve to the correctly specialized sub-routines that it calls. (e.g. a call from within integrate<10>() to some other templated function would automatically use the correct rate group).
Edit: Here's a more fleshed out description of some desireable properties.
- probably the single biggest feature would be design time compiler warnings. Let's say a particular function
foois not allowed in a fast rate group, I want to ensure that any top-level function tree I call never callsfoo<10>but is allowed to callfoo<100>. The above really requires that there be a mechanism to instantiate templates by context. E.g. a function withtemplate<int rate_group>would automatically instantiate any functions it calls with the rate group.
Examples:
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();
}
Using bar<100> should work just fine, but trying to build bar<10> should result in a compile-time assertion.
The key for the above feature to function is being able to give any C++ block a contextual rate-group attribute and by default pass that on to any calls made within that block.
building on top of #1, templates would have an ordering of rate groups to disallow using slower than self rate-group functions:
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 }
These two features alone would already go a long way. However, both depend on the automated maintenance of the property. I'm not sure C++ allows for this level of meta-coding.