1

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

4
  • note: even if there is a solution in this very special case (for example, a very special for_each), I really want to know how to create function templates like mine which will work in all cases Commented Nov 1, 2009 at 0:11
  • arr in calculate()'s definition is not a template parameter (should be a typename) not a variable. Commented Nov 1, 2009 at 0:11
  • I'm trying to create a function callback with already defined parameter, smth like this Commented Nov 1, 2009 at 0:13
  • Murali, how to make it a variable? I need it like a second parameter Commented Nov 1, 2009 at 0:14

4 Answers 4

4

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));
Sign up to request clarification or add additional context in comments.

8 Comments

templates don't need to be parameterized by type specifically. template<int n> works just fine. However the template argument needs to be resolvable at compile-time.
so, template<int n> works, but template<multimap<string, double> arr> doesn't? I thought there're equal
template<int n> works if and only if the int you actually use to instantiate the template is known at compile-time.
template<int n> doesn't take n as a parameter at all. It only takes a compile time constant. You seem to be confused at how this works. Even if if you had an int instead of a multimap, it doesn't work the way you're trying to use it.
template<multimap<string, double> arr> doesn't work, but template<multimap<string, double> &arr> works fine if provided with a correct argument.
|
2

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:

  • Only non-local variables can be passed and only non-static variables - variables with internal linkage can't be used.
  • It's very strange, and will confuse most C++ programmers.

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.

Comments

0

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.

1 Comment

and what's the solution? (if any)
0

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);

3 Comments

I always prefer to make calculate a class and let it hold a reference to the map as a member.
This one doesn't work, because for_each will copy the function object and return the final one. But you don't use its return value.
I had assumed that the work is done in the calculate method, not by means of its return value.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.