Reputation: 14423
I'll paste the relevant code only
Template class:
template<class TMsgType, class TKeyType>
struct mapped_subscription_handler
{
protected:
typedef std::function<void(TKeyType const &, TMsgType*)> handler_t;
typedef std::unordered_multimap<TKeyType, subscr_obj<handler_t>> map_t;
public:
void call(TKeyType const & key, TMsgType* msg)
{
//blah
}
public:
handler_id_t register_handler(TKeyType const & key, handler_t handler)
{
//blah
}
void unregister_handler(TKeyType key, handler_id_t id)
{
//blah
}
private:
map_t _map;
};
Implementation class:
typedef clients::mapped_subscription_handler<NS_Snap::NS_MD::DepSnapshot, clients::header_info<NS_Snap::NS_DEF::Header>::mdid_t> depth_handler_t;
typedef clients::mapped_subscription_handler<NS_Snap::NS_MD::TrdSnapshot, clients::header_info<NS_Snap::NS_DEF::Header>::mdid_t> trd_handler_t;
class data_client
:public depth_handler_t,
public trd_handler_t
{
public:
data_client(const std::string & host, int port);
virtual ~data_client();
clients::handler_id_t register_on_connect(std::function<void()> connect_handler);
using depth_handler_t::register_handler;
using trd_handler_t::register_handler;
using depth_handler_t::unregister_handler;
using trd_handler_t::unregister_handler;
};
Usage:
class time_comparer
{
internal_clients::data_client *_int_client;
void whenever()
{
//Compiler complains about ambiguous call here.
_int_client->register_handler(rep->GetId(), boost::bind(&time_comparer::on_internal_depth, this, _1, _2));
}
void on_internal_depth(uint64_t const & key, NS_Snap::NS_MD::DepSnapshot* depth)
{
//blah
}
};
The compiler complains of ambiguous reference when I call register_handler
. Shouldn't it be able to identify which register_handler
I am calling (based on boost::bind
type)? Otherwise I have to qualify the call with the class name which is ugly.
EDIT:
Based on input from Sebastian Redl
This simpler example encounters the same problem
#include <iostream>
#include <functional>
template<class T>
struct test_template
{
template<class TArg>
void do_(T t, TArg arg)
{
t(arg);
}
};
class test_class :
public test_template<std::function<void(char*)>>,
public test_template<std::function<void(int)>>
{
public:
using test_template<std::function<void(char*)>>::do_;
using test_template<std::function<void(int)>>::do_;
};
int main()
{
test_class tc;
tc.do_([](int x){std::cout << x << std::endl; }, 10);
tc.do_([](char* x) {std::cout << x << std::endl; }, "what");
return 0;
}
Is there any way around this without explicitly specifying the overload when calling? i.e.
tc.test_template<std::function<void(int)>>::do_([](int x){std::cout << x << std::endl; }, 10);
Upvotes: 0
Views: 155
Reputation: 218278
In the simplified example, you may use SFINAE to remove template based mostly on the non function argument.
template<class T>
struct test_template
{
template<class TArg>
auto do_(T t, TArg arg)
-> decltype(t(arg), void())
{
t(arg);
}
};
Upvotes: 2
Reputation: 72142
std::function
is very liberal in conversions to it, and in particular the standard doesn't require the conversion to be SFINAEd out if the passed function object isn't compatible. So both function types appear to be constructable from the binds, which is why you get an ambiguity.
Upvotes: 0