error: passing `const ...' as `this' argument of `...' discardsqualifiers

  • Thread starter Giovanni Gherdovich
  • Start date
G

Giovanni Gherdovich

Hello,

I'm doing some toy experiments to see how
the algoritm std::transform and the function
adapter std::bind2nd can play together, but
my compiler give my the error

error: passing `const traslate' as `this' argument of
`circle traslate::eek:perator()(circle, std::vector<double,
std::allocator<double> >)'
discards qualifiers

It should be like I'm trying to modify
something which is declared as const...

The example code follows.

I define the type `circle', which holds
center and radius of a circle, then I
introduce a vector of circles and try to
traslate them all with std::transform.
I need std::bind2nd to fix the traslation
for all the circles.
Note that I'm forced to define the
temporary object `traslate' to meet
std::bind2nd input specifications.

// =======================================
#include <vector>
#include<functional>
#include<algorithm>
using namespace std;

struct circle
{
vector<double> center;
double radius;
};

struct traslate
{
typedef circle first_argument_type;
typedef vector<double> second_argument_type;
typedef circle result_type;
circle operator()(const circle original, const vector<double>
traslation)
{
circle traslated = original;
traslated.center[0] += traslation[0];
traslated.center[1] += traslation[1];
return traslated;
}
};

int main()
{
vector<circle> lots_of_circles(10);
vector<circle> some_other_circles(10);
vector<double> traslation(2);
traslation[0] = 123;
traslation[1] = 321;
transform(lots_of_circles.begin(), lots_of_circles.end(),
some_other_circles.begin(), bind2nd(traslate(), traslation));
}
// =======================================

Can you see the reason of the above mentioned error?

Regards,
Giovanni Gh.
 
M

mlimber

Hello,

I'm doing some toy experiments to see how
the algoritm std::transform and the function
adapter std::bind2nd can play together, but
my compiler give my the error

error: passing `const traslate' as `this' argument of
`circle traslate::eek:perator()(circle, std::vector<double,
std::allocator<double> >)'
discards qualifiers

It should be like I'm trying to modify
something which is declared as const...

The example code follows.

I define the type `circle', which holds
center and radius of a circle, then I
introduce a vector of circles and try to
traslate them all with std::transform.
I need std::bind2nd to fix the traslation
for all the circles.
Note that I'm forced to define the
temporary object `traslate' to meet
std::bind2nd input specifications.

// =======================================
#include <vector>
#include<functional>
#include<algorithm>
using namespace std;

struct circle
{
  vector<double> center;

How about std::pair instead? Or, perhaps even better, make your own
point class with members x and y. std::vector is overkill here.
  double radius;

};

struct traslate
{
 typedef circle first_argument_type;
 typedef vector<double> second_argument_type;
 typedef circle result_type;

Consider inheriting from std::binary_function instead of this.
 circle operator()(const circle original, const vector<double>
traslation)

You probably want to use references for both of these parameters to
prevent unnecessary copies. (They may be inlined away or relatively
trivial here, but maybe not if you call this a lot.) You should also
use std::pair or your own point class here, too, since you only have x
and y coordinates. Since this function doesn't modify the object's
state, it should be made const (note also the references):

circle operator()(
const circle& original,
const vector<double>& traslation) const
{ ... }

However, since your functor has no state, you should just make this a
plain old function rather than a function object.
 {
   circle traslated = original;
   traslated.center[0] += traslation[0];
   traslated.center[1] += traslation[1];
   return traslated;
 }

};

int main()
{
  vector<circle> lots_of_circles(10);
  vector<circle> some_other_circles(10);
  vector<double> traslation(2);
  traslation[0] = 123;
  traslation[1] = 321;
  transform(lots_of_circles.begin(), lots_of_circles.end(),
some_other_circles.begin(), bind2nd(traslate(), traslation));}

// =======================================

Can you see the reason of the above mentioned error?

You're creating a temporary object -- the instance of translate --
which is bound to a const reference in bind2nd. The function you are
calling is not const. Add const to the member function, or better,
make it a plain old function.

See these FAQs for more info on const-correctness:

http://www.parashift.com/c++-faq-lite/const-correctness.html

Cheers! --M
 
G

Giovanni Gherdovich

Thank you; you answer even more than
what I've asked and I appreciate it a lot.
How about std::pair instead

I agree. And since I don't need any method
for these points, std::pair will do the job.
Consider inheriting from std::binary_function
instead of this.

Cool!
So I can avoid to explicitly rename my types with the
tedious

typedef circle first_argument_type;
However, since your functor has no state, you should just make this a
plain old function rather than a function object.

True, but if I do that I cannot use the algorithm std::tranform,
wich save me from looping explicitly over the circles (wich I
find is cool), because I cannot use std::bind2nd
(which wants a function object as first argument).
You're creating a temporary object -- the instance of translate --
which is bound to a const reference in bind2nd. The function you are
calling is not const. Add const to the member function

Exactly.
Thank you, also for the reference to the FAQs.

But let me understand: std::bind2nd onbly accept _const_ member
functions a input function object?

Cheers,
Giovanni
 
M

mlimber

I agree. And since I don't need any method
for these points, std::pair will do the job.

Right, though struct Point { double x,y; }; may make your code easier
to read and only requires reinventing a very, very small wheel. :)
True, but if I do that I cannot use the algorithm std::tranform,
wich save me from looping explicitly over the circles (wich I
find is cool), because I cannot use std::bind2nd
(which wants a function object as first argument).

With ordinary functions, just use std::ptr_fun to wrap them for
std::transform et al.:

circle Translate1( const circle original, const vector<double>
traslation)
{ /* code from traslate::eek:perator() */ }

// ...
transform(lots_of_circles.begin(), lots_of_circles.end(),
some_other_circles.begin(),
bind2nd(ptr_fun(Translate), traslation));

You may notice I omitted the references from the parameters to
Translate1 because, unfortunately, the standard binders currently
don't allow reference arguments. For more on this problem, see
http://www.boost.org/doc/libs/1_35_0/libs/utility/call_traits.htm#refs

Alternately, if you have the standard library extensions known as TR1
or if you have Boost (where most of those extensions originated), you
could use reference arguments with the generalized binder
(std::tr1::bind or boost::bind) instead of std::bind2nd:

// Note ref params
circle Translate2( const circle& original, const vector<double>&
traslation)
{/*same code*/}

// ...

// TR1 version
transform(lots_of_circles.begin(), lots_of_circles.end(),
some_other_circles.begin(),
std::tr1::bind(
Translate2,
std::tr1::placeholders::_1,
traslation) );

// Easier-to-read version of the above:
using namespace std::tr1;
using namespace std::tr1::placeholders;

transform(lots_of_circles.begin(), lots_of_circles.end(),
some_other_circles.begin(), bind( Translate2, _1, traslation) );


// Boost version
transform(lots_of_circles.begin(), lots_of_circles.end(),
some_other_circles.begin(), boost::bind(Translate2, _1,
traslation) );

For more on these, see Pete Becker's article:

http://www.ddj.com/cpp/184401949

or his book on TR1, or the Boost.Bind documentation.
But let me understand: std::bind2nd onbly accept _const_ member
functions a input function object?

Yes. The enhanced binders correct this and other "inconveniences" with
the standard binders.

Cheers! --M
 
G

Giovanni Gherdovich

Dear Mlimber,
With ordinary functions, just use std::ptr_fun to wrap them for
std::transform et al.:

this information is precious.
I was wondering how to use std::bind2nd without building
ad-hoc function object...
You may notice I omitted the references from the parameters to
Translate1 because, unfortunately, the standard binders currently
don't allow reference arguments. For more on this problem, see
http://www.boost.org/doc/libs/1_35_0/libs/utility/call_traits.htm#refs

Alternately, if you have the standard library extensions known as TR1
or if you have Boost

Mmmh... I was not aware of that.
I may have to review my design, or to use Pete Becker's TR1 or Boost
as you suggest.
The point is that I have to call a code analogous to the circles'
one...
a few millions of times.
And as you told,
You probably want to use references for both of these parameters to
prevent unnecessary copies. (They may be inlined away or relatively
trivial here, but maybe not if you call this a lot.)

I will study this issue.

Cheers,
Giovanni
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top