Question

What's wrong with the following snippet ?

#include <tr1/functional>
#include <functional>
#include <iostream>

using namespace std::tr1::placeholders;

struct abc
{
    typedef void result_type;

    void hello(int)
    { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    void hello(int) const
    { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    abc()
    {}
};

int
main(int argc, char *argv[])
{
    const abc x;
    int a = 1;

    std::tr1::bind(&abc::hello, x , _1)(a);
    return 0;
}

Trying to compile it with g++-4.3, it seems that cv-qualifier overloaded functions confuse both tr1::mem_fn<> and tr1::bind<> and it comes out the following error:

no matching function for call to ‘bind(<unresolved overloaded function type>,...

Instead the following snippet compiles but seems to break the const-correctness:

struct abc
{
    typedef void result_type;

    void operator()(int)
    { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    void operator()(int) const
    { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    abc()
    {}
};

...

    const abc x;
    int a = 1;
    std::tr1::bind( x , _1)(a);

Any clue?

Was it helpful?

Solution

The lookup is done at a time when the constness of this is not known. You just have to give it a hint via casting. Try this:

typedef void (abc::*fptr)(int) const; // or remove const
std::tr1::bind((fptr)&abc::hello, x , _1)(a);

You may also notice here that removing the const still works. This is because you should be passing x by pointer (because the first argument to a C++ member function, the implicit this parameter, is always a pointer). Try this instead:

typedef void (abc::*fptr)(int) const; // won't compile without const (good!)
std::tr1::bind((fptr)&abc::hello, &x , _1)(a);

As discovered during within my comments below, if you omit the & as you originally did, you'll be passing x by value, which is usually not what you want (though it makes little practical difference in your particular example). This actually seems like an unfortunate pitfall for bind.

OTHER TIPS

This question has been answered, but I find the best way to specify an overload with bind is to specify it on the template:

std::tr1::bind<void(foo::*)(int)>(&foo::bar);

This method is just as explicit, but shorter than casting (with static_cast anyway. But it's cleaner than the C-cast, which is the same length.

As John suggested, the problems arisen in those snippets are the following:

  1. When passing a member-function-pointer it's necessary to specify its signature (if overloaded)
  2. bind() are passed arguments by value.

The first problem is solved by casting the member function pointer provided to bind:

    std::tr1::bind(static_cast< void(abc::*)(int) const >(&abc::hello), x, _1)(a);

The second can be solved by passing the callable object by address (as John suggested), or by means of TR1 reference_wrapper<> -- otherwise it will be passed by value, making the const-correctness breaking hallucination.

Given x a callable object:

std::tr1::bind( std::tr1::ref(x) , _1)(a);

bind() will forward a to the proper operator() in accordance to the x constness.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top