I want to code some header file whose inclusion allows me to then write template for-loops in an accessible syntax. How do I implement this? (cf. at the bottom for my best attempt).
There follows an example and criteria of what is meant with an accessible syntax.
Example:
for_loop<int,i0,ic,iE>(i){ // for(int i=i0;i<iE;i+=ic), where i0,ic,iE are constexpr int
foo(i);
bar<i>();
for_loop<int,i,1,10>(j){
boo<i,j>();
}
}
Criteria
As met by the example, useful criteria for an accessible syntax are:
- the scope of each for-loop is braced
- there is no boilerplate (like creation of a lambda functions, functor classes, index sequences, confusing artifacts like
()
,[]
,,...
that enhance readability neither of loop range nor loop body, etc.) - the accessibility of variables and functions from within the braced scope is identical to a classical for-loop.
- desirable: the use of
<>
notation forint,i0,ic,iE
as to indicate them as template arguments. // the use of(i)
is because I assume we need a Macro there for the symboli
Related questions are presented here:
- [https://stackoverflow.com/questions/13816850/is-it-possible-to-develop-static-for-loop-in-c]
- [https://stackoverflow.com/questions/1032602/template-ing-a-for-loop-in-c]
- [https://stackoverflow.com/questions/42019564/how-to-iterate-over-stdindex-sequence]
These questions, however, focus on the achievement of functionality. The focus of this question instead is explicitly on the achievement of an accessible syntax.
Best Attempt
The following is my best functioning attempt yet at achieving a solution:
# define template_for_loop_begin(index) \
[&]<std::size_t... index>(std::index_sequence<index...>) {
# define template_for_loop_end(index,N) ;}(std::make_index_sequence<N>{});
// this allows writing a template for-loop as follows:
template_for_loop_begin(i)(
bar<i>(),...
)template_for_loop_end(i,10)
However, the resulting syntax is unsatisfactory. Issues are:
- major: the loop body is limited to one single line
- major: the loop body must be a single function call
- semi: there is
,...
instead of;
at the end of the line - semi: the indexing is in the footer of the loop
- minor the loop brackets are
()
instead of{}
Example of a Normal For Loop and what Problems it poses
A real-world code example is a following customer's code, using my spline library.
for(int i=0;i<1000;++i){
int j=i;
spline.load(j,data[j]);
}
This works fine. Now some employees have gotten to bad ideas, like:
for(int i=0;i<500;++i){
if(data[i]>0){ j=i+500;}else{j=i;}
spline.load(j,data[i]);
}
My software uses automatic code transformation based on a run-time that produces source code. In order for this source code transformation to yield my intended behaviour, the index j
must be a constexpr. Hence, I would like to make it template. However, I cannot educate the customer into relearning a way of writing for-loops that discourages/demotivates them from using my code. Which leads to this question.
Templates, Consteval, and Constexpr, and Type
Thanks for Yakk - Adam Nevraumont's kindly provided answer, we can use static_foreach
below:
#include <utility>
template<auto first, auto increment, auto limit>
struct static_foreach_t {
void operator->*( auto f ) const& {
[&]<auto...Is>(std::integer_sequence<decltype(first), Is...>) {
( f( std::integral_constant<decltype(Is), first+Is*increment>{} ), ...);
}( std::make_integer_sequence< decltype(first), (limit-first)/increment >{} );
}
};
template<auto first, auto increment, auto limit>
constexpr static_foreach_t<first, increment, limit> static_foreach = {};
// ++++
template<typename T>
struct Cxpr{
const T t;
consteval Cxpr(T t):t(t){}
};
void foo(int){}
void bar(Cxpr<int>){}
template<int> void boo(void){}
int main(){
static_foreach<3, 2, 7>->*[&](auto i) {
foo(i);
//bar(i);
boo<i>();
};
}
However, it the code throws an error error: could not convert 'i' from 'std::integral_constant<int, 3>' to 'Cxpr<int>'
when uncommenting bar(i);
, which is a consteval. Can this be solved? I tried various constructors and assigment overloads for Cxpr
. Another game-breaker is that it does not work with float and double, as, e.g., in my spline library there are also functions that only prevent misuse if floating-point numbers can be asserted to be of constexpr/consteval type.