returned type of boost::bind && Address of a tmp object

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

  1. Hello,

    in the following code I have a pointer (to function), say p,
    of type
    double (*)(double, double, void*)
    and I try to fix the second argument of the function *p
    to a given value (using boost::bind), but the compiler
    complains, because of a type mismatch in an assignment
    which I think should be legal:

    /*
    * bash-3.00$ g++ function.cpp
    * function.cpp: In function `int main()':
    * function.cpp:36: warning: taking address of temporary
    * function.cpp:36: error: cannot convert
    * `boost::_bi::bind_t<double,
    * double (*)(double, double, void*),
    * boost::_bi::list3<boost::arg<1>,
    *
    boost::_bi::value<double>,
    * boost::arg<2> > >*'
    * to `double (*)(double, void*)' in assignment
    */

    Can you see why? The code is below.

    There is also a warning which I don't like at all,
    and remebers me that boost::bind( ... ) is a temporary
    object and its address makes sense only in the current
    scope (if I'm not wrong).
    Since I have to pass this address as argument to another
    function (later, in my real code), this can couse problems.

    How can I build a "real" (I mean non-temporary) object
    out of boost::bind( ... ), so that its address can
    be passed forth and back across my code?

    Regards,
    Giovanni


    // ---------------------------------------------- the file
    function.cpp
    #include <boost/bind.hpp>

    struct oneVar_function // one variable function
    {
    double (* function) (double x, void* params);
    void* params;
    };

    struct twoVar_function // two variables function
    {
    double (* function) (double x, double y, void* params);
    void* params;
    };

    double
    my_function (double x, double y, void* params)
    {
    // I cast `params` to double*.
    // The user will be kind enough to always
    // give a double* as 3rd argument when
    // calling my_function.
    double* alpha = static_cast<double*>(params);
    return x + y + *alpha; // or whatever
    }

    int main()
    {
    twoVar_function f;
    oneVar_function g;

    f.function = &my_function;
    double alpha = 3;
    f.params = &alpha;

    double a_given_number = 2;
    g.function = &(boost::bind(*(f.function),
    _1,
    a_given_number,
    _2));
    g.params = &alpha;
    }
    // -------------------------------------- end of the file function.cpp
     
    Giovanni Gherdovich, Aug 28, 2008
    #1
    1. Advertising

  2. Giovanni Gherdovich

    Guest

    On Aug 28, 2:18 pm, Giovanni Gherdovich
    <> wrote:
    > Hello,
    >
    > in the following code I have a pointer (to function), say p,
    > of type
    > double (*)(double, double, void*)
    > and I try to fix the second argument of the function *p
    > to a given value (using boost::bind), but the compiler
    > complains, because of a type mismatch in an assignment
    > which I think should be legal:
    >
    > /*
    >  *  bash-3.00$ g++ function.cpp
    >  *  function.cpp: In function `int main()':
    >  *  function.cpp:36: warning: taking address of temporary
    >  *  function.cpp:36: error: cannot convert
    >  *         `boost::_bi::bind_t<double,
    >  *                             double (*)(double, double, void*),
    >  *                             boost::_bi::list3<boost::arg<1>,
    >  *
    > boost::_bi::value<double>,
    >  *                                               boost::arg<2> > >*'
    >  *           to `double (*)(double, void*)' in assignment
    >  */
    >


    The compiler message says that the result of boost::bind is not
    convertible to a function pointer.
    boost::bind is a function template which returns an object (the type
    of this object is a function of the parameters passed to the
    boost::bind invocation), not an "ordinary" function.

    The warning about taking the address of a temporary is because your
    code takes the address of that object returned by boost::bind.

    > How can I build a "real" (I mean non-temporary) object
    > out of boost::bind( ... ), so that its address can
    > be passed forth and back across my code?


    Have a look at boost::function: http://www.boost.org/doc/libs/1_36_0/doc/html/function.html

    HTH,

    Éric Malenfant
     
    , Aug 28, 2008
    #2
    1. Advertising

  3. Giovanni Gherdovich

    gpderetta Guest

    On Aug 28, 8:18 pm, Giovanni Gherdovich
    <> wrote:
    > Hello,
    >
    > in the following code I have a pointer (to function), say p,
    > of type
    > double (*)(double, double, void*)
    > and I try to fix the second argument of the function *p
    > to a given value (using boost::bind), but the compiler
    > complains, because of a type mismatch in an assignment
    > which I think should be legal:
    >


    <snip>
    >
    > Can you see why? The code is below.
    >
    > There is also a warning which I don't like at all,
    > and remebers me that boost::bind( ... ) is a temporary
    > object and its address makes sense only in the current
    > scope (if I'm not wrong).
    > Since I have to pass this address as argument to another
    > function (later, in my real code), this can couse problems.
    >
    > How can I build a "real" (I mean non-temporary) object
    > out of boost::bind( ... ), so that its address can
    > be passed forth and back across my code?
    >


    <snip>
    > struct oneVar_function  // one variable function
    > {
    >   double (* function) (double x, void* params);
    >   void* params;
    >
    > };


    <snip>

    >
    >   double a_given_number = 2;
    >   g.function = &(boost::bind(*(f.function),
    >                              _1,
    >                              a_given_number,
    >                              _2));


    'Bind' does not return a function pointer but an unspecified function
    object (sort of a closure).

    Thus there are two problems: first the assignment is illegal: you are
    trying to convert a pointer to such a function object to a pointer to
    a function. Second, as the compiler warns you, grabbing the address of
    the temporary object returned by bind is a dangerous action, because
    the temporary will be destroyed at the end of the expression.

    As the exact result type of 'bind' is unspecified (well, you can see
    it in the error message, but you shouldn't rely on it), you will have
    to use boost::function as the type of the 'function' member of
    oneVar_function:

    #include <boost/function.hpp>
    struct oneVar_function // one variable function
    {
    boost::function<double (double x, void* params)> function;
    void* params;
    };

    [note: unteste code]
    Note that boost::function can store function pointers as well as
    function objects.

    --
    gpd
     
    gpderetta, Aug 28, 2008
    #3
  4. Hello,

    thank you for your answers.

    Eric:
    > Have a look at boost::function


    gpd:
    > As the exact result type of 'bind' is unspecified (well, you can see
    > it in the error message, but you shouldn't rely on it), you will have
    > to use boost::function as the type of the 'function' member of
    > oneVar_function: [...]


    I implemented my (wanna-be) callbacks as boost::function instead of
    function pointers, and the two problems I mentioned in my previous
    post are gone.

    Furthermore I feel that switching the whole design of my real code
    to boost::function will be straightforward. Cool!

    Here is the modified version of my toy example, which compiles
    and works fine:

    // ---------------- this is the file function2.cpp
    #include <boost/bind.hpp>
    #include <boost/function.hpp>
    #include <iostream>

    struct oneVar_function // one variable function
    {
    boost::function<double (double x, void* params)> function;
    void* params;
    };

    struct twoVar_function // two variables function
    {
    boost::function<double (double x, double y, void* params)> function;
    void* params;
    };

    double
    my_function (double x, double y, void* params)
    {
    // I cast `params` to double*.
    // The user will be kind enough to always
    // give a double* as 3rd argument when
    // calling my_function.
    double* alpha = static_cast<double*>(params);
    return x + y + *alpha; // or whatever
    }

    int main()
    {
    double alpha = 3;
    twoVar_function f;
    oneVar_function g;

    f.function = &my_function;
    f.params = &alpha;

    double a_given_number = 2;
    g.function = boost::bind(f.function,
    _1,
    a_given_number,
    _2);
    g.params = &alpha;

    std::cout << (f.function)(1, 2, f.params) << std::endl;
    // expected: 6
    std::cout << (g.function)(1, g.params) << std::endl;
    // expected: 6

    /*
    * bash-3.00$ g++ function2.cpp
    * bash-3.00$ ./a.out
    * 6
    * 6
    * bash-3.00$
    */
    }
    // ---------------- end of file function2.cpp
     
    Giovanni Gherdovich, Aug 28, 2008
    #4
    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. sherazi
    Replies:
    3
    Views:
    523
    Roedy Green
    Oct 25, 2005
  2. Toby Bradshaw
    Replies:
    6
    Views:
    1,814
    Kai-Uwe Bux
    Jun 2, 2006
  3. Replies:
    0
    Views:
    614
  4. Christopher
    Replies:
    1
    Views:
    861
    Yakov Gerlovin
    Oct 5, 2011
  5. Mark
    Replies:
    1
    Views:
    468
    Jeff Flinn
    Nov 25, 2012
Loading...

Share This Page