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

Discussion in 'C++' started by Giovanni Gherdovich, Aug 12, 2008.

  1. 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.
    Giovanni Gherdovich, Aug 12, 2008
    #1
    1. Advertising

  2. Giovanni Gherdovich

    mlimber Guest

    On Aug 12, 9:23 am, Giovanni Gherdovich
    <> wrote:
    > 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
    mlimber, Aug 12, 2008
    #2
    1. Advertising

  3. Thank you; you answer even more than
    what I've asked and I appreciate it a lot.

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

    >
    > How about std::pair instead


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

    > > 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.


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

    typedef circle first_argument_type;
    typedef vector<double> second_argument_type;
    typedef circle result_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
    Giovanni Gherdovich, Aug 12, 2008
    #3
  4. Giovanni Gherdovich

    mlimber Guest

    On Aug 12, 10:57 am, Giovanni Gherdovich
    <> wrote:
    > > How about std::pair instead

    >
    > 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. :)

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


    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
    mlimber, Aug 12, 2008
    #4
  5. std::bind2nd without function objects / pass-by-reference and

    Dear Mlimber,

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

    >
    > 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
    Giovanni Gherdovich, Aug 13, 2008
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Neo
    Replies:
    1
    Views:
    542
    Victor Bazarov
    Mar 28, 2006
  2. Lycan. Mao..
    Replies:
    4
    Views:
    3,301
    Lycan. Mao..
    Mar 4, 2007
  3. Replies:
    11
    Views:
    1,087
  4. Javier
    Replies:
    2
    Views:
    543
    James Kanze
    Sep 4, 2007
  5. 0m
    Replies:
    26
    Views:
    1,090
    Tim Rentsch
    Nov 10, 2008
Loading...

Share This Page