Preliminary
A functions-family is a countable list of functions y=f_i(x), for a counter i=0,...,n-1 for some integer n.
Minimum example
I have a derived struct in c++ that shall define such a functions-family for n=3:
template<typename Tfloat, size_t n> Base{
template<size_t i> bool f(Tfloat* x){ static_assert(i<n); return false; }
};
template<typename Tfloat>
struct Derived: Base<Tfloat,3>{
template<> bool f<0>(Tfloat* x){ x[3]-=x[2]; return true; }
template<> bool f<1>(Tfloat* x){ x[1]*=x[3]; return true; }
template<> bool f<2>(Tfloat* x){ if(x[5]==0) return false; x[2]/=x[5]; return true; }
};
Question
How can I achieve the following?:
- force by virtue of inheritance from Base<Tfloat,3> at compile-time that all three functions of the family are defined.
- I need to be able to statically loop through f with, e.g. an
std::sequence<n>. Until now, I have given a different namef0, f1,...to each function. But then one must manually write anif constexpr(i=0){ return f0(x); }wrapper to traverse through all names in the definition oftemplate<size_t i> f(Tfloat* x). Acutally, this is how I am doing it as of now. - Be able to write the definitions within the body of Derived.
Issues
I know that there are a dozen of issues:
- one cannot specialize a template function within the scope of Derived.
- one cannot even specialize a template function of an un-specialized Derived at all.
- and while a call of
f<i>fori>=ncan be statically prohibited, I see no way to enforce definedness for alli=0,...,n-1.
Thus I am very curious for your ideas.
Remarks
- Typically, the functions for different
ihave very little to do with one another; e.g., physical models for thei-th stage of a rocket. I prefer the use of template forsize_t i. - Derived typically holds run-time dependent parameters and data computed/initialized from these parameters. Hence, the use of a namespace instead of struct for Derived appears unsuitable to me.
Proposal: Function Array
Taken from @HolyBlackCat's comment:
#include<iostream>
#include<functional>
#include<array>
template<typename Tfloat, size_t n>
class Base{
protected:
std::array<std::function<bool(Tfloat*)>,n> f_;
public:
// probably here in conjunction with an invalid default initialize for each element of f_, CRTP could be used to assert after construction of derived that each f_[i] is defined?
template<size_t i>
bool f(Tfloat* x){ return f_[i](x); } // accessor prevents external overwrite into f_.
};
template<typename Tfloat>
class Derived: public Base<Tfloat,3>{
public:
//
Derived(){
Base<Tfloat,3>::f_[0] = [this](Tfloat* x){
x[0] *= x[1];
return true;
};
}
//
};
template<typename Tfloat>
struct NaiveDerived{
//
bool f0(Tfloat* x){
x[0] *= x[1];
return true;
}
//
};
int main(){
Derived<float> d;
float x[10];
d.f[0](x);
}
This code works and achieves the requirements 2 and 3.
I do not like the use of a function array much because eventually we want to marry two things:
- a function body of the i-th function
{ x[0]*=x[1]; return true; } - a template function name of the i-th function
f<i>(x)
Introducing f_ into the mix only accomplishes to avoid giving names to each function body before we assign said body to its respective f<i>. More readable would be a solution that states the i-th function body directly with f<i>.
If you might change signature, i.e calling
d.f(IC<0>{}, x);and notd.f<0>(x);Following might help, using
virtualto ensure functions existence:Demo