Note: This entry has been restored from old archives.
I had a hard time Googling a solution to this particular woe. Alas the exact string “unresolved overloaded function type
” doesn’t give anything useful with “boost::bind
” and “boost:mem_fn
“. This is the typical sort error message from g++
:
foo.cpp:18: error: no matching function for call to 'bind(<unresolved overloaded function type>, const boost::reference_wrapper<FooMaster>, boost::arg<1> (&)())'
I’ve generated this using a rather contrived example based on the use pattern that was causing my woe:
#include <iostream> #include <boost/bind.hpp> class FooMaster { public: void foo(std::string &s) { std::cout << "foo(s=" << s << ")" << std::endl; } void foo(int x) { std::cout << "foo(x=" << x << ")" << std::endl; } }; int main(int argc, char **argv) { FooMaster fm; boost::bind(&FooMaster::foo, boost::ref(fm), _1)(10); return 0; }
The problem is obvious of course, it is exactly as the compiler is telling you. Mr compiler has no idea which “foo
” you’re talking about. “But Mr Compiler, it is obvious!” You say. “I’m not passing it a bloody string!” Sometimes you just have to understand that Mr Compiler isn’t you and needs a little hand-holding.
The issue clearly boils down to FooMaster
having two methods that match &FooMaster::foo
. This signature, used to instantiate the bind
template, doesn’t take into account the arguments, so which foo
are we taling about?! Alas, as obvious as the problem was I didn’t find the solution so obvious. I just don’t cut it as a C++ guy sometimes. I’d given up on the problem in fact, but then I stumbled on a solution while looking into some other problem I had. It was one of those “oh, duh!” moments really, I was looking at some code that assigned a member function pointer. The type specification for such a thing includes the argument types! So here’s a modified main
that uses one extra step in order to explain what we want to the compiler:
int main(int argc, char **argv) { FooMaster fm; // Create a variable of the desired function signature type and assign // using desired member function. This will resolve the correct // function thanks to the signature including the argument types. void (FooMaster::*fn)(int) = &FooMaster::foo; // Now pass the function variable to the template method so that it knows // exactly which function we mean. boost::bind(fn, boost::ref(fm), _1)(10); return 0; }
All you have to do is give Mr Compiler a little bit of a helping handβ¦
Joy!
hi Yvan, when I saw the solution to your presented problem above the first time I thought wow, great this does also solve my problem but then after some time I concluded that this works only in some particular cases. It works as long as the input arguments in the overloaded functions are not derived from the same abstract class. Just think of the visitor pattern where you might have several overloaded functions where some input arguments are derived from the same class and a container which keeps any kind of class which is derived from our base abstract class. If you walk now through each object in the container and try to bind them to the particular visit function you will get a compile time error as the compiler is not able to resolve the overloaded function type. In my mind this problem is specific to boost bind as it loses type information. So please let me now when you got a more general solution.
Best regards,
Rudi
Hi Yvan, thank you for that fast replay. You’re right I meant something which is slightly different to your proposed solution π In your solution above, the ‘visit( const Base* inst ) method is always called no matter if it was a derived object or not. So what I wanted is that the right visit function shall be called depending on the object’s type. I now, I could have solved this with double dispatch mechanism as it is explained in ‘Alexandrescu’s Moder C++ Design’ but in my mind this does not work in conjunction with boost bind. I modified your code so you can see what I meant. However, I think there do exist better solutions but haven’t found them yet:-)
#include <string>
#include <iostream>
#include <list>
#include <algorithm>
#include <boost/bind.hpp>
class Visitor;
class Base
{
public:
Base(const std::string & str) : m_str(str)
{};
virtual ~Base()
{};
const std::string & getStr() const
{
return m_str;
}
virtual void accept( Visitor& v ) = 0;
private:
std::string m_str;
};
class DerivedOne : public Base
{
public:
DerivedOne() : Base(“DerivedOne”)
{};
virtual ~DerivedOne()
{};
void accept( Visitor& v );
};
class DerivedTwo : public Base
{
public:
DerivedTwo() : Base(“DerivedTwo”)
{};
virtual ~DerivedTwo()
{};
void accept( Visitor& v );
};
class Visitor
{
public:
void visit( Base * inst)
{
inst->accept( *this );
}
void visit(const DerivedOne * inst)
{
std::cout << “<1>Foo: ” << inst->getStr() << std::endl;
}
void visit(const DerivedTwo * inst)
{
std::cout << “<2>Foo: ” << inst->getStr() << std::endl;
}
};
void DerivedOne::accept( Visitor& v )
{
v.visit( this );
}
void DerivedTwo::accept( Visitor& v )
{
v.visit( this );
}
int main()
{
std::list<Base *> baseList;
baseList.push_back(new DerivedOne);
baseList.push_back(new DerivedTwo);
baseList.push_back(new DerivedTwo);
baseList.push_back(new DerivedOne);
Visitor visitor;
void (Visitor::*visit)(Base *inst) = &Visitor::visit;
std::for_each(baseList.begin(), baseList.end(), boost::bind(visit, boost::ref(visitor), _1));
return 0;
}
I compiled it with g++ 4.1.2!
Best regard,
Rudi.
Hi Rudi,
The solution I have is sufficient for the problem I hit, I wasn’t planning on making it more general! π
I’m not quite sure of the scenario you’re describing though. If you map a particular function with a funtion pointer it’ll lock to exactly the function matching the signature (and there can’t be multiple of these in a class.) So the method for binding above should still work, as in the following example (fingers crossed that my comment submission will handle this!):
———————————–
#include <string>
#include <iostream>
#include <list>
#include <algorithm>
#include <boost/bind.hpp>
class Base
{
public:
Base(const std::string & str)
: m_str(str)
{};
virtual ~Base()
{};
const std::string & getStr() const
{ return m_str; }
private:
std::string m_str;
};
class DerivedOne : public Base
{
public:
DerivedOne().
: Base(“DerivedOne”)
{};
virtual ~DerivedOne()
{};
};
class DerivedTwo : public Base
{
public:
DerivedTwo().
: Base(“DerivedTwo”)
{};
virtual ~DerivedTwo()
{};
};
class Visitor
{
public:
void visit(const Base * inst)
{ std::cout << inst->getStr() << std::endl; }
void visit(const DerivedOne * inst)
{ std::cout << “Foo: ” << inst->getStr() << std::endl; }
void visit(const std::string & str)
{ std::cout << str << std::endl; }
};
int main()
{
std::list<Base *> baseList;
baseList.push_back(new DerivedOne);
baseList.push_back(new DerivedTwo);
baseList.push_back(new DerivedTwo);
baseList.push_back(new DerivedOne);
Visitor visitor;
void (Visitor::fn)(const Base inst) = &Visitor::visit;
std::for_each(baseList.begin(), baseList.end(), boost::bind(fn, boost::ref(visitor), _1));
return 0;
}
———————————–
This code compiles and runs on for me, with g++ 4.1.3. My guess is that you probably mean something different to what I think. π
Your code does what I’d do in your situation. It has the advantage of being fundamental C++ that anyone should understand (always a good thing!)
What is “better”? Less code? Less indirection? (I.e. performance.)
I guess the issue could be performance… if this is part of very tight performance critical code then I think you’d want to reconsider the entire design π
Another common approach to your problem, coming from C, is to create your own jump table (or switch statement) based on a type identifier. This isn’t very C++y though, but it can help with performance. Similar would be some sort of registration and execution of a fn ptr, callback style.
Hrm, and templates aren’t other going to help because you’re after runtime evaluation.
I suppose you’re probably looking for elegance? In which case C-style solutions aren’t it π I’d be interested to know if you do find a solution that meets your criteria for “better.” (And what the criteria are as well, of course!)