c++ - Desambiguar el puntero de función miembro sobrecargado que se pasa como parámetro de plantilla
templates c++11 (1)
El problema está aquí:
l.call(&foo::func, "hello");
l.call(&foo::func, 0.5);
Para ambas líneas, el compilador 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<void (foo::*)(const std::string&)>(&foo::func), "hello");
l.call(static_cast<void (foo::*)(const double )>(&foo::func), 0.5);
Alternativamente, puede proporcionar los argumentos de la plantilla que el compilador no puede deducir y que definen el tipo de func
:
l.call<void, const std::string&>(&foo::func, "hello");
l.call<void, double >(&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.
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 intento 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 <iostream>
#include <vector>
#include <algorithm>
template<typename Class>
struct observer_list
{
template<typename Ret, typename... Args, typename... UArgs>
void call(Ret (Class::*func)(Args...), UArgs&&... args)
{
for (auto obj : _observers)
{
(obj->*func)(std::forward<UArgs>(args)...);
}
}
std::vector<Class*> _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<foo> 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 compilar 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<Args, UArgs>>
para std::enable_if<std::is_convertible<Args, UArgs>>
, 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í?