tags:

views:

86

answers:

1
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <functional>
#include <deque>
using namespace std;

#include <tr1/functional>
using namespace std::tr1::placeholders;
template<class Function_t>
void for_each_x(Function_t func,int interval)
{
   for(int sc = 0; sc < 10; sc+=interval){
      func((const int)sc);
   }
}
void foo(int x,const int y)
{
}

int main(int argc, char *argv[])
{
   for_each_x(tr1::bind(tr1::function<void(int,const int)>(foo),_1,11),2);
   return 0;
}

gcc 4.2.2 or 4.4.1 gives very long error message. if I change the "const int" to "int", then no error message. But I really like to have the "const int" to make sure the counter variable doesn't changed by accident if the function's argument is passed by reference.

+2  A: 

An expression is not only classified by its type, but also by its lvalueness. This one mostly determines whether it's stored somewhere, and it also determines whether it can be bound to non-const references. A non-const rvalue (non-lvalue) cannot be bound to non-const references, so if you do the following, you always fail:

template<typename T>
void f(T&);
int main() { f(10); f((int const)10); }

The second call may surprise you, but actually cv-qualifiers are dropped from non-class rvalues, and so the cast expression happens to have the type int, still. So the function template's parameter type will be deduced to int& - compilation fails.

Now, pre-C++0x bind does only support non-const references as the type of argument it forwards, so if you give it a const argument it's fine - its templated parameter will make it so it becomes a const reference. But if you give it a non-const argument, and it's an rvalue, it's not fine, because it won't be able to be bound by the reference parameter.

You want to call the bind object with an lvalue - that is, with sc or with it cast to a const lvalue. Notice also that toplevel qualifiers of function parameter types are dropped, and so foo effectively has type void(int, int) - this toplevel cv-dropping happens for all types of parameters. Anyway, the solution is to change the call to

for(int sc = 0; sc < 10; sc+=interval){
   func((int const&)sc); // notice &
}
Johannes Schaub - litb