In the following example, I would like a traverse method that receives a callback. This example works perfectly as soon as I don't capture anything [] because the lambda can be reduced into a function pointer. However, in this particular case, I would like to access sum.
struct Collection {
int array[10];
void traverse(void (*cb)(int &n)) {
for(int &i : array)
cb(i);
}
int sum() {
int sum = 0;
traverse([&](int &i) {
sum += i;
});
}
}
What is the proper way (without using any templates) to solve this? A solution is to use a typename template as follows. But in this case, you lack visibility on what traverse gives in each iteration (an int):
template <typename F>
void traverse(F cb) {
for(int &i : array)
cb(i);
}
Lambda types are unspecified; there is no way to name them.
So you have two options:
Make traverse a template (or have it take auto, which is effectively the same thing)
Fortunately this is a completely normal and commonplace thing to do.
Have traverse take a std::function<void(int)>. This incurs some overhead, but does at least mean the function need not be a template.
But in this case, you lack visibility on what traverse gives in each iteration (an int)
We don't tend to consider that a problem. I do understand that giving this in the function's type is more satisfying and clear, but generally a comment is sufficient, because if the callback doesn't provide an int, you'll get a compilation error anyway.
Only captureless lambdas can be used with function pointers. As every lambda definition has its own type you have to use a template parameter in all places where you accept lambdas which captures.
But in this case, you lack visibility on what traverse gives in each iteration (an int).
This can be checked easily by using SFINAE or even simpler by using concepts in C++20. And to make it another step simpler, you even do not need to define a concept and use it later, you can directly use an ad-hoc requirement as this ( this results in the double use of the requires keyword:
struct Collection {
int array[10];
template <typename F>
// check if F is "something" which can be called with an `int&` and returns void.
requires requires ( F f, int& i) { {f(i)} -> std::same_as<void>; }
void traverse(F cb)
{
for(int &i : array)
cb(i);
}
// alternatively you can use `std::invocable` from <concepts>
// check if F is "something" which can be called with an `int&`, no return type check
template <std::invocable<int&> F>
void traverse2(F cb)
{
for(int &i : array)
cb(i);
}
int sum() {
int sum = 0;
traverse([&](int &i) {
sum += i;
});
return sum;
}
};
In your case you have several ways of declaring a callback in C++:
Function pointer
void traverse(void (*cb)(int &n)) {
for(int &i : array)
cb(i);
}
This solution only supports types that can decay into a function pointer. As you mentioned, lambdas with captures would not make it.
Typename template
template <typename F>
void traverse(F cb) {
for(int &i : array)
cb(i);
}
It does accept anything, but as you noticed. the code is hard to read.
Standard Functions (C++11)
void traverse(std::function<const void(int &num)>cb) {
for(int &i : array)
cb(i);
}
This is the most versatile solution with a slightly overhead cost.
Don't forget to include <functional>.
Related
I am working with a library which exposes an interface to work with. One of the functions of this library is like this :
template <int a>
void modify(){}
I have to modify parameters from 1 to 10 i.e. call modify with with template arguments from 1 to 10. For that I wrote this code (a basic version of code, actual code is much larger).
for(int i=0; i<10; i++){
modify<i>();
}
On compilation I receive the following error
error: 'i' cannot appear in constant-expression
After going through some links on the internet, I came to know that I cannot pass any value as template argument which is not evaluated at compile time.
My question are as follows:
1. Why can't compiler evaluate i at compile time?
2. Is there any other to achieve the objective I am trying to achieve without changing the API interface?
There is another thing I want to do. Call modify as modify where VAR is the output of some functional computation. How can I do that?
What is the value of i (that is not a constant) at compile time? There is no way to answer unless executing the loop. But executing is not "compiling"
Since there is no answer, the compiler cannot do that.
Templates are not algorithm to be executed, but macros to be expanded to produce code.
What you can do is rely on specialization to implement iteration by recursion, like here:
#include <iostream>
template<int i>
void modify()
{ std::cout << "modify<"<<i<<">"<< std::endl; }
template<int x, int to>
struct static_for
{
void operator()()
{ modify<x>(); static_for<x+1,to>()(); }
};
template<int to>
struct static_for<to,to>
{
void operator()()
{}
};
int main()
{
static_for<0,10>()();
}
Note that, by doing this, you are, in fact, instantiating 10 functions named
modify<0> ... modify<9>, called respectively by static_for<0,10>::operator() ... static_for<9,10>::operator().
The iteration ends because static_for<10,10> will be instantiated from the specialization that takes two identical values, that does nothing.
"Why can't compiler evaluate i at compile time?"
That would defeat the purpose of templates. Templates are there for the case where the source code looks the same for some set of cases, but the instructions the compiler needs to generate are different each time.
"Is there any other to achieve the objective I am trying to achieve without changing the API interface?"
Yes, look at Boost.MPL.
However I suspect the right answer here is that you want to change the API. It depends on the internals of the modify function. I know you have it's source, because templates must be defined in headers. So have a look why it needs to know i at compile time and if it does not, it would be best to replace (or complement if you need to maintain backward compatibility) it with normal function with parameter.
Since you asked for an answer using Boost.MPL:
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/range_c.hpp>
#include <iostream>
template <int N>
void modify()
{
std::cout << N << '\n';
}
// You need to wrap your function template in a non-template functor
struct modify_t
{
template <typename N>
void operator()(N)
{
modify<N::value>();
}
};
int main()
{
namespace mpl = boost::mpl;
mpl::for_each< mpl::range_c<int,0,10> >( modify_t() ); // prints 0 to 9
}
Without using struct or Boost it can also be done :
#include <iostream>
#include <utility>
template <int a>
void modify()
{
std::cout<<a<<",";
}
template<int i,size_t... t>
constexpr inline void CT_for_impl(std::integer_sequence<size_t,t...>)
{
bool kai[]= { (modify<i+t>(), false)...};
}
template<int i,int n>
constexpr inline void CT_for()
{
CT_for_impl<i>(std::make_index_sequence<n-i+1>());
}
int main()
{
CT_for<-5,5>();
return 0;
}
Given you want to call the functions at run-time by their index and you can't change the API, you can consider type-erasure:
std::vector<std::function<void(int)> > func;
func.push_back(modify<1>);
func.push_back(modify<2>);
//... and so on ...
func.push_back(modify<10>);
for(int i=0; i<10; ++i)
{
func[i](); //calls modify<i+1>();
}
Some points to mention:
That's not what templates are primarily for, but it's a way to bring a static library to the run-time world. The basic requirement for this is that one works with homogeneous types (--if modify<7>() would return, say, a std::string the whole approach would break).
The previous solution using type-erasure has an overhead. One can maybe get it faster by using function pointers, but still it will always be slower than calling the functions at compile time.
One can (and should) also wrap the push_backs into another iterative static function to avoid the manual calls.
solution to error: 'i' cannot appear in constant-expression for the above problem
To read about constexpr click this link
#include <iostream>
using namespace std;
template <typename T>
void modify(T a)
{
cout<<a<<endl; //to check if its working
}
//func converts int a into const int a
constexpr int func(int a)
{
return a;
}
int main(){
for(int i=0; i<10; i++){
modify(func(i));//here passing func(i) returned value which can be used as template argument now as it is converted to constexpr
}
return 0;
}
I am working on a part of a program that applies different types of filters onto an already read data part of a bitmap image. The method in question gets the data stored in a 2-dim std::vector and furthermore a pointer to the function in which the filter is applied as arguments. By that we can generically apply different filters by using this method.
My question is, are function pointers the only way to achieve this, or does C++ offer a more beautiful and more readable solution to achieve it?
This is the method this question is about. Second argument is the function pointer that is used to access the function in the if/else statement inside the for loops.
void SteganoMessage::genFilter(std::vector<std::vector<uint32_t>> *d, uint32_t (*f)(uint32_t, size_t)){
int count = 0;
int pixel = getPixel();
for(auto itOuter = d->begin(); itOuter != d->end(); ++itOuter){
for(auto itInner = itOuter->begin(); itInner != itOuter->end(); ++itInner){
if(mode == true)
*itInner = f(*itInner, sizeof(*itInner));
else
*itInner = f(*itInner, this->getImage()->getBitmapHeader()->getBitCount()/8);
displayProgress(count, pixel);
}
}
displayProgress(0);
}
Call of genFilter function:
//...
{
genFilter(data, substB);
}
//...
While substB is a function of course.
Would be very thankful for a hint that leads me into the right direction where I could research or a code snippet that shows a possible more C++ like way to do it.
Type-preserving
The usual way to pass a function (or things that can be INVOKEd) in C++ is by using a template parameter:
// version #1
template <typename F>
void func(F f)
{
static_assert(std::is_invocable_v<F, std::uint32_t, std::size_t>);
// instead of f(*itInner, sizeof(*itInner))
std::invoke(f, *itInner, sizeof(*itInner));
}
You can also use SFINAE to prevent postponing the error to instantiation time. This also enables overloading:
// version #2
template <typename F>
std::enable_if_t<std::is_invocable_v<F, std::uint32_t, std::size_t>>
func(F f)
{
// no need to static_assert here
std::invoke(f, *itInner, sizeof(*itInner));
}
Since C++20, we can use concepts:
// version #3
template <std::Invocable<std::uint32_t, std::size_t> F>
void func(F f)
{
// same as above
}
Which can be simplified further, using an abbreviated function template, to:
// version #4
void func(std::Invocable<std::uint32_t, std::size_t> auto f)
{
// same as above
}
(This is still a function template rather than an ordinary function. It is equivalent to version #3.)
Type-erasing
You can also use std::function for type erasure:
// version #5
void func(std::function<void(std::uint32_t, std::size_t)> f)
{
// ...
f(*itInner, sizeof(*itInner));
}
Compared to the type-preserving alternatives (versions #1–4), this approach may reduce code bloat, but may incur runtime overhead for virtual function calling.
I agree with the already suggested comments and answer.
But if your question was about finding a way to avoid to pass a raw pointer to function as arguments and gain more control over the given filters, I think you can create a wrapping class with a functor that will handle the applied filters.
What is the motivation behind doing this ? Because a raw pointer to function does not give you the guarantee that the function is what you expect. You can pass any function which respect the prototype but is not a real filter and can do anything.
You can solve this problem this way (explanation below the code):
enum class FILTER_TYPE {MY_FILTER, MY_OTHER_FILTER};
class Filter
{
protected:
FILTER_TYPE f_type;
public:
Filter(FILTER_TYPE ft) : f_type(ft)
{}
uint32_t operator()(uint32_t a, size_t b) const
{
switch(f_type)
{
case FILTER_TYPE::MY_FILTER: return my_filter(a, b);
case FILTER_TYPE::MY_OTHER_FILTER: return my_other_filter(a, b);
}
}
private:
uint32_t my_filter(uint32_t a, size_t b) const
{
return a+static_cast<uint32_t>(b); // completely arbitrary
}
uint32_t my_other_filter(uint32_t a, size_t b) const
{
return a*static_cast<uint32_t>(b); // completely arbitrary
}
};
As you can see, you define all your different filters in the private section. Then you redefine the operator() in order to call the proper filter (selected by the FILTER_TYPE attribute).
Then, you can write your function this way:
void SteganoMessage::genFilter(std::vector <std::vector <uint32_t>> & data, const Filter & filter)
{
int count = 0;
int pixel = getPixel();
for(auto itOuter = data.begin(); itOuter != data.end(); ++itOuter)
{
for(auto itInner = itOuter->begin(); itInner != itOuter->end(); ++itInner)
{
if(mode == true)
*itInner = filter(*itInner, sizeof(*itInner));
else
*itInner = filter(*itInner, this->getImage()->getBitmapHeader()->getBitCount()/8);
displayProgress(count, pixel);
}
}
displayProgress(0);
}
This way, you have the guarantee that the argument is a well-defined filter, and you avoid the use of raw pointer to function (that make the code more readable).
I redefined the operator() in order to use the Filter instance as a function. It makes the code more intuitive in my opinion.
Last thing, I passed the data by reference instead of the address directly.
I hope it can be a good additional information.
The ultimate goal of this is to have a function which can take a variable number of arguments of a certain type (the same type, not different types), that can be declared on the function call.
As I'm using Visual Studio 2010, I CANNOT do:
MyFunction({1,2,3});
In an earlier question which was answered, I found I could use boost::assign::list_of(), however I discovered later that this seems to have a bug of some kind if you try to pass it only one parameter.
So I did some more searching and found that I could use variadic functions to achieve what I was aiming for.
void TestFunction2<int>(int count, ...)
{}
However, I wanted to restrict it by type, so eventually found I could do this with templates:
template <class T>
void TestFunction(const T& count, ...);
template <>
void TestFunction<int>(const int& count, ...);
Unfortunately, varargs things like va_list do not apparently like references. The examples I saw to restrict types like this used const references. If I remove the const reference aspect of the count parameter, it works as I want, but I don't know if this is going to lead to horrible side-effects down the road, OR if this whole varargs thing is a bad idea to begin with.
So I guess my question is, is what I'm doing in the last example above good or bad? If it's bad, what is a good alternative so I can call a function with one or more parameters in-line like, say, int parameters?
What you want is std::initializer_list<T>, unfortunately this require C++11 support.
An alternative, that is nearly as elegant and easy enough to upgrade from, is to use an array:
#include <iostream>
template <typename T, size_t N>
void func(T (&s)[N]) {
for (size_t i = 0; i != N; ++i) {
std::cout << s[i] << '\n';
}
}
int main() {
int array[] = {1, 2, 3};
func(array);
}
When you move on to a compiler that supports initializer lists, this can be changed into:
#include <iostream>
template <typename T>
void func(std::initializer_list<T> s) {
for (T const& t: s) {
std::cout << t << '\n';
}
}
int main() {
func({1, 2, 3});
}
So both the function and call sites update will be painless.
Note: the call site could be made completely similar using a macro, I advise against such approach, the purported gain is not worth the obfuscation.
EDIT:
One more solution... if your compiler's IDE partially supports C++11, you may be able to initialize a std::vector at call time, i.e.
template <typename T>
void TestFunction(std::vector<T> vect)
{
....
}
....
TestFunction(std::vector<int>{1,2,3});
Advantages to this approach are that STL automatically frees the allocated memory when the function goes out of scope.
If that doesn't work you can resort to a two liner...
template <typename T>
void TestFunction(std::vector<T> vect)
{
....
}
....
std::vector<int> tmp(1,2,3);
TestFunction(tmp);
The big downside is that here the memory sits on stack until you leave that scope (or explicitly resize the vector to zero length.
Both approaches share some advantages... the count is built in and you have access to other useful member functions or affiliate methods (like std::sort).
......................................
Why not use variable arguments?
See the answer here, for example...
Is it a good idea to use varargs in a C API to set key value pairs?
On non-C+11 compliant compilers (like your IDE), you can try...
template <typename T>
TestFunction(const unsigned int count, T * arr)
TestFunction<std::string>(10, new string[] {"One", "Two", "Three"});
(Sounds like you can't use this in your IDE, but...)
If you're confident you're only compiling on modern machines and are primarily using simple types, this is best/most standards compliant solution...
As of C++11 you can use std::initializer which is in std::vector:
#include<vector>
template <typename T>
void TestFunction(const std::initializer_list<T>& v)
{ }
int main()
{
TestFunction<double>({1.0, 2.0});
return 0;
}
..........................
...however this requires your compiler to be C+11 so it's not perfectly portable. For anything other than simple types, it also becomes harder to read.
I realize you say on the function call, but you may want to rethink that from a readability and ease of coding approach.
I agree with part of your approach -- what you want is to use a template function (this handles the variable type). Before you call you initialize your collection of same-type elements into a temporary standard C array or a std::vector/std::list (STL's array wrapper).
http://www.cplusplus.com/doc/tutorial/templates/
http://www.cplusplus.com/reference/vector/
http://www.cplusplus.com/reference/list/
It's more lines of code, but it's much more readable and standardized.
i.e.
Rather than...
MyFunction({1,2,3});
Use:
template <typename T>
void TestFunction(const int count, T * arr)
{
for (unsigned int i = 0; i < count; i++)
{
.... arr[i] ... ; //do stuff
...
}
}
int main()
{
int * myArr = {1,2,3};
TestFuntion<int>(3, myArr);
}
...or...
#include <vector>
template <typename T>
void TestFunction(std::vector<T> vect)
{
for (unsigned int i = 0; i < vect.size(); i++)
{
.... vect[i] ... ; //do stuff
...
}
}
int main()
{
std::vector<int> myVect;
myVect.push_back(1);
myVect.push_back(2);
myVect.push_back(3);
TestFuntion<int>(myVect);
}
std::list would also be a perfectly acceptable, and may perform better, depending on your use case.
I have a this function to read 1d arrays from an unformatted fortran file:
template <typename T>
void Read1DArray(T* arr)
{
unsigned pre, post;
file.read((char*)&pre, PREPOST_DATA);
for(unsigned n = 0; n < (pre/sizeof(T)); n++)
file.read((char*)&arr[n], sizeof(T));
file.read((char*)&post, PREPOST_DATA);
if(pre!=post)
std::cout << "Failed read fortran 1d array."<< std::endl;
}
I call this like so:
float* new_array = new float[sizeof_fortran_array];
Read1DArray(new_array);
Assume Read1DArray is part of a class, which contains an ifstream named 'file', and sizeof_fortran_array is already known. (And for those not quite so familiar with fortran unformatted writes, the 'pre' data indicates how long the array is in bytes, and the 'post' data is the same)
My issue is that I have a scenario where I may want to call this function with either a float* or a double*, but this will not be known until runtime.
Currently what I do is simply have a flag for which data type to read, and when reading the array I duplicate the code something like this, where datatype is a string set at runtime:
if(datatype=="float")
Read1DArray(my_float_ptr);
else
Read1DArray(my_double_ptr);
Can someone suggest a method of rewriting this so that I dont have to duplicate the function call with the two types? These are the only two types it would be necessary to call it with, but I have to call it a fair few times and I would rather not have this duplication all over the place.
Thanks
EDIT:
In response to the suggestion to wrap it in a call_any_of function, this wouldnt be enough because at times I do things like this:
if(datatype=="float")
{
Read1DArray(my_float_ptr);
Do_stuff(my_float_ptr);
}
else
{
Read1DArray(my_double_ptr);
Do_stuff(my_double_ptr);
}
// More stuff happening in between
if(datatype=="float")
{
Read1DArray(my_float_ptr);
Do_different_stuff(my_float_ptr);
}
else
{
Read1DArray(my_double_ptr);
Do_different_stuff(my_double_ptr);
}
If you think about the title you will realize that there is a contradiction in that the template instantiation is performed at compile time but you want to dispatch based on information available only at runtime. At runtime you cannot instantiate a template, so that is impossible.
The approach you have taken is actually the right one: instantiate both options at compile time, and decide which one to use at runtime with the available information. That being said you might want to think your design.
I imagine that not only reading but also processing will be different based on that runtime value, so you might want to bind all the processing in a (possibly template) function for each one of the types and move the if further up the call hierarchy.
Another approach to avoid having to dispatch based on type to different instantiations of the template would be to loose some of the type safety and implement a single function that takes a void* to the allocated memory and a size argument with the size of the type in the array. Note that this will be more fragile, and it does not solve the overall problem of having to act on the different arrays after the data is read, so I would not suggest following this path.
Because you don't know which code path to take until runtime, you'll need to set up some kind of dynamic dispatch. Your current solution does this using an if-else which must be copied and pasted everywhere it is used.
An improvement would be to generate a function that performs the dispatch. One way to achieve this is by wrapping each code path in a member function template, and using an array of member function pointers that point to specialisations of that member function template. [Note: This is functionally equivalent to dynamic dispatch using virtual functions.]
class MyClass
{
public:
template <typename T>
T* AllocateAndRead1DArray(int sizeof_fortran_array)
{
T* ptr = new T[sizeof_fortran_array];
Read1DArray(ptr);
return ptr;
}
template <typename T>
void Read1DArrayAndDoStuff(int sizeof_fortran_array)
{
Do_stuff(AllocateAndRead1DArray<T>(sizeof_fortran_array));
}
template <typename T>
void Read1DArrayAndDoOtherStuff(int sizeof_fortran_array)
{
Do_different_stuff(AllocateAndRead1DArray<T>(sizeof_fortran_array));
}
// map a datatype to a member function that takes an integer parameter
typedef std::pair<std::string, void(MyClass::*)(int)> Action;
static const int DATATYPE_COUNT = 2;
// find the action to perform for the given datatype
void Dispatch(const Action* actions, const std::string& datatype, int size)
{
for(const Action* i = actions; i != actions + DATATYPE_COUNT; ++i)
{
if((*i).first == datatype)
{
// perform the action for the given size
return (this->*(*i).second)(size);
}
}
}
};
// map each datatype to an instantiation of Read1DArrayAndDoStuff
MyClass::Action ReadArrayAndDoStuffMap[MyClass::DATATYPE_COUNT] = {
MyClass::Action("float", &MyClass::Read1DArrayAndDoStuff<float>),
MyClass::Action("double", &MyClass::Read1DArrayAndDoStuff<double>),
};
// map each datatype to an instantiation of Read1DArrayAndDoOtherStuff
MyClass::Action ReadArrayAndDoOtherStuffMap[MyClass::DATATYPE_COUNT] = {
MyClass::Action("float", &MyClass::Read1DArrayAndDoOtherStuff<float>),
MyClass::Action("double", &MyClass::Read1DArrayAndDoOtherStuff<double>),
};
int main()
{
MyClass object;
// call MyClass::Read1DArrayAndDoStuff<float>(33)
object.Dispatch(ReadArrayAndDoStuffMap, "float", 33);
// call MyClass::Read1DArrayAndDoOtherStuff<double>(542)
object.Dispatch(ReadArrayAndDoOtherStuffMap, "double", 542);
}
If performance is important, and the possible set of types is known at compile time, there are a few further optimisations that could be performed:
Change the string to an enumeration that represents all the possible data types and index the array of actions by that enumeration.
Give the Dispatch function template parameters that allow it to generate a switch statement to call the appropriate function.
For example, this can be inlined by the compiler to produce code that is (generally) more optimal than both the above example and the original if-else version in your question.
class MyClass
{
public:
enum DataType
{
DATATYPE_FLOAT,
DATATYPE_DOUBLE,
DATATYPE_COUNT
};
static MyClass::DataType getDataType(const std::string& datatype)
{
if(datatype == "float")
{
return MyClass::DATATYPE_FLOAT;
}
return MyClass::DATATYPE_DOUBLE;
}
// find the action to perform for the given datatype
template<typename Actions>
void Dispatch(const std::string& datatype, int size)
{
switch(getDataType(datatype))
{
case DATATYPE_FLOAT: return Actions::FloatAction::apply(*this, size);
case DATATYPE_DOUBLE: return Actions::DoubleAction::apply(*this, size);
}
}
};
template<void(MyClass::*member)(int)>
struct Action
{
static void apply(MyClass& object, int size)
{
(object.*member)(size);
}
};
struct ReadArrayAndDoStuff
{
typedef Action<&MyClass::Read1DArrayAndDoStuff<float>> FloatAction;
typedef Action<&MyClass::Read1DArrayAndDoStuff<double>> DoubleAction;
};
struct ReadArrayAndDoOtherStuff
{
typedef Action<&MyClass::Read1DArrayAndDoOtherStuff<float>> FloatAction;
typedef Action<&MyClass::Read1DArrayAndDoOtherStuff<double>> DoubleAction;
};
int main()
{
MyClass object;
// call MyClass::Read1DArrayAndDoStuff<float>(33)
object.Dispatch<ReadArrayAndDoStuff>("float", 33);
// call MyClass::Read1DArrayAndDoOtherStuff<double>(542)
object.Dispatch<ReadArrayAndDoOtherStuff>("double", 542);
}
I am working with a library which exposes an interface to work with. One of the functions of this library is like this :
template <int a>
void modify(){}
I have to modify parameters from 1 to 10 i.e. call modify with with template arguments from 1 to 10. For that I wrote this code (a basic version of code, actual code is much larger).
for(int i=0; i<10; i++){
modify<i>();
}
On compilation I receive the following error
error: 'i' cannot appear in constant-expression
After going through some links on the internet, I came to know that I cannot pass any value as template argument which is not evaluated at compile time.
My question are as follows:
1. Why can't compiler evaluate i at compile time?
2. Is there any other to achieve the objective I am trying to achieve without changing the API interface?
There is another thing I want to do. Call modify as modify where VAR is the output of some functional computation. How can I do that?
What is the value of i (that is not a constant) at compile time? There is no way to answer unless executing the loop. But executing is not "compiling"
Since there is no answer, the compiler cannot do that.
Templates are not algorithm to be executed, but macros to be expanded to produce code.
What you can do is rely on specialization to implement iteration by recursion, like here:
#include <iostream>
template<int i>
void modify()
{ std::cout << "modify<"<<i<<">"<< std::endl; }
template<int x, int to>
struct static_for
{
void operator()()
{ modify<x>(); static_for<x+1,to>()(); }
};
template<int to>
struct static_for<to,to>
{
void operator()()
{}
};
int main()
{
static_for<0,10>()();
}
Note that, by doing this, you are, in fact, instantiating 10 functions named
modify<0> ... modify<9>, called respectively by static_for<0,10>::operator() ... static_for<9,10>::operator().
The iteration ends because static_for<10,10> will be instantiated from the specialization that takes two identical values, that does nothing.
"Why can't compiler evaluate i at compile time?"
That would defeat the purpose of templates. Templates are there for the case where the source code looks the same for some set of cases, but the instructions the compiler needs to generate are different each time.
"Is there any other to achieve the objective I am trying to achieve without changing the API interface?"
Yes, look at Boost.MPL.
However I suspect the right answer here is that you want to change the API. It depends on the internals of the modify function. I know you have it's source, because templates must be defined in headers. So have a look why it needs to know i at compile time and if it does not, it would be best to replace (or complement if you need to maintain backward compatibility) it with normal function with parameter.
Since you asked for an answer using Boost.MPL:
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/range_c.hpp>
#include <iostream>
template <int N>
void modify()
{
std::cout << N << '\n';
}
// You need to wrap your function template in a non-template functor
struct modify_t
{
template <typename N>
void operator()(N)
{
modify<N::value>();
}
};
int main()
{
namespace mpl = boost::mpl;
mpl::for_each< mpl::range_c<int,0,10> >( modify_t() ); // prints 0 to 9
}
Without using struct or Boost it can also be done :
#include <iostream>
#include <utility>
template <int a>
void modify()
{
std::cout<<a<<",";
}
template<int i,size_t... t>
constexpr inline void CT_for_impl(std::integer_sequence<size_t,t...>)
{
bool kai[]= { (modify<i+t>(), false)...};
}
template<int i,int n>
constexpr inline void CT_for()
{
CT_for_impl<i>(std::make_index_sequence<n-i+1>());
}
int main()
{
CT_for<-5,5>();
return 0;
}
Given you want to call the functions at run-time by their index and you can't change the API, you can consider type-erasure:
std::vector<std::function<void(int)> > func;
func.push_back(modify<1>);
func.push_back(modify<2>);
//... and so on ...
func.push_back(modify<10>);
for(int i=0; i<10; ++i)
{
func[i](); //calls modify<i+1>();
}
Some points to mention:
That's not what templates are primarily for, but it's a way to bring a static library to the run-time world. The basic requirement for this is that one works with homogeneous types (--if modify<7>() would return, say, a std::string the whole approach would break).
The previous solution using type-erasure has an overhead. One can maybe get it faster by using function pointers, but still it will always be slower than calling the functions at compile time.
One can (and should) also wrap the push_backs into another iterative static function to avoid the manual calls.
solution to error: 'i' cannot appear in constant-expression for the above problem
To read about constexpr click this link
#include <iostream>
using namespace std;
template <typename T>
void modify(T a)
{
cout<<a<<endl; //to check if its working
}
//func converts int a into const int a
constexpr int func(int a)
{
return a;
}
int main(){
for(int i=0; i<10; i++){
modify(func(i));//here passing func(i) returned value which can be used as template argument now as it is converted to constexpr
}
return 0;
}