Search code examples
c++c++11functional-programmingtr1

tr1::mem_fn and tr1::bind: on const-correctness and overloading


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?


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.