Reputation: 10095
I'm trying to start learning C++ and I have a problem.
I'm trying to create a function template,
template<multimap<string, double> arr>
void calculate(string key) {
}
and use it like this:
multimap<string, double> arr;
vector<string> keys;
// ...
for_each(keys.begin(), keys.end(), calculate<arr>);
But i doesnt'complile:
Illegal type for non-type parameter, etc
Please, help me. How to arhive the behavior I expect? I really don't want to create a callback for every for_each, etc. (Maybe, closures have made me more lazy than it needed for C++ and I have to, but I don't want to believe)
(btw, is there a way to get a vector with keys from multimap?)
I've tried
typedef multimap<string, double> my_map;
template<my_map arr>
still doen't work
Upvotes: 1
Views: 486
Reputation: 507373
It's wrong to say flat-out that a template parameter can only be a type or an integer. It can be more than that, including a reference or pointer. But you cannot have it a map
as a value parameter. So, even though the preferred way to write your code is to write a functor with an operator()
, you can still pass a map as a template argument.
template<multimap<string, double> &arr>
void calculate(string key) {
}
multimap<string, double> arr;
int main() {
vector<string> keys;
for_each(keys.begin(), keys.end(), &calculate<arr>);
}
You should be aware of the consequences:
So to summarize: Don't do it - but it's good to know that you can do it, and i think it's important to say the full truth, even though it may seem confusing at times.
Upvotes: 2
Reputation: 156278
Many dynamic languages (and a few fancy compiled languages, like c++0x!) have something called closures, which are like functions, but also are first class objects in the sense that they wrap up some local state where they are used.
Regular C++ doesn't have this. Fortunately C++ doesn't care if template arguments are real functions or some other odd thing that works when you try to use operator()
on it. broadly, these are known as functors, which is what you need here.
struct calculate {
multimap<string, double> arr;
void operator()(string key) {
}
};
Using it is quite similar.
multimap<string, double> arr;
vector<string> keys;
calculate Calc;
Calc.arr = arr;
// ...
for_each(keys.begin(), keys.end(), Calc);
Upvotes: 0
Reputation: 67847
I don't know what you're trying to do, but templates are parameterized by type. An ordinary function or a function object should do what you want.
So let's make your function look like this:
void calculate(const string &key, multimap<string, double>& myMap)
{
// do something...
}
now we can use the STL's binders and ptr_fun
to convert your function to an object and bind its second argument to your map.
multimap<string, double> map1;
vector<string> v = getValuesForMyVector();
for_each(v.begin(), v.end(), bind2nd(ptr_fun(calculate), map1);
So what's going on is that ptr_fun(calculate)
converts calculate
, which is a pointer-to-function, into a special class called a pointer_to_binary_function<string, multimap<string, double>, void>
which has operator()
defined to call your function, i.e. it takes 2 parameters.
bind2nd(ptr_fun(calculate), map1)
returns a binder2nd<string, void>
which still has operator()
defined, but now it only takes 1 parameter. The 2nd parameter is bound to map1. This allows for_each
to operate with this function object.
Of course, you're stuck using these 2 adaptors if you make a function. A better way is to make a class:
class MapCalculator
{
public:
MapCalculator(multimap<string, double>& destination) : map_(destination) {}
void operator()(const string& s)
{
// do something...
}
private:
multimap<string, double>& map_;
};
// later...
multimap<string, double> map1;
vector<string> v = getValuesForMyVector();
for_each(v.begin(), v.end(), MapCalculator(map1));
Upvotes: 4
Reputation: 370435
You can't use objects created at run-time as template arguments. Templates are instantiated at compile-time, so all template parameters need to be known at compile-time.
Upvotes: 0