Desambiguar el puntero de función miembro sobrecargado que se pasa como parámetro de plantilla

Estoy intentando recrear el patrón Observer en el que puedo reenviar parámetros perfectamente a una función miembro dada de los observadores.

Si bash pasar la dirección de una función miembro que tiene varias anulaciones , no puede deducir la función de miembro correcta en función de los argumentos.

#include  #include  #include  template struct observer_list { template void call(Ret (Class::*func)(Args...), UArgs&&... args) { for (auto obj : _observers) { (obj->*func)(std::forward(args)...); } } std::vector _observers; }; struct foo { void func(const std::string& s) { std::cout << this << ": " << s << std::endl; } void func(const double d) { std::cout << this << ": " << d << std::endl; } }; int main() { observer_list l; foo f1, f2; l._observers = { &f1, &f2 }; l.call(&foo::func, "hello"); l.call(&foo::func, 0.5); return 0; } 

Esto no se puede comstackr con template argument deduction/substitution failed .

Tenga en cuenta que tenía Args... y UArgs... porque necesito poder pasar parámetros que no son necesariamente del mismo tipo que el tipo de firma de la función, pero son convertibles a dicho tipo.

Estaba pensando que podría usar una std::enable_if<std::is_convertible> para std::enable_if<std::is_convertible> , pero no creo que pueda hacer esto con un paquete de parámetros de plantilla variadica.

¿Cómo puedo hacer que la deducción de argumento de la plantilla funcione aquí?

El problema está aquí:

 l.call(&foo::func, "hello"); l.call(&foo::func, 0.5); 

Para ambas líneas, el comstackdor no sabe a qué foo::func se refiere. Por lo tanto, debe desambiguarse proporcionando la información de tipo que falta (es decir, el tipo de foo:func ) mediante moldes:

 l.call(static_cast(&foo::func), "hello"); l.call(static_cast(&foo::func), 0.5); 

Alternativamente, puede proporcionar los argumentos de la plantilla que el comstackdor no puede deducir y que definen el tipo de func :

 l.call(&foo::func, "hello"); l.call(&foo::func, 0.5); 

Tenga en cuenta que debe usar double y no const double arriba. La razón es que generalmente double y const double son dos tipos diferentes. Sin embargo, hay una situación en la que double y const double se consideran como si fueran del mismo tipo: como argumentos de función. Por ejemplo,

 void bar(const double); void bar(double); 

no son dos sobrecargas diferentes, pero en realidad son la misma función.