Últimamente escribí una función de plantilla para resolver algunas repeticiones de código. Se parece a esto:
template<class T, class R, class... Args>
R call_or_throw(const std::weak_ptr<T>& ptr, const std::string& error, R (T::*fun)(Args...), Args... args) {
if (auto sp = ptr.lock())
{
return std::invoke(fun, *sp, args...);
}
else
{
throw std::runtime_error(error.c_str());
}
}
int main() {
auto a = std::make_shared<A>();
call_or_throw(std::weak_ptr<A>(a), "err", &A::foo, 1);
}
Este código funciona perfectamente bien para lo class Aque se ve así:
class A {
public:
void foo(int x) {
}
};
Pero no puede compilar para uno como este:
class A {
public:
void foo(const int& x) {
}
};
¿Por qué es así (por qué quiero decir por qué no puede deducir el tipo) y cómo (si es posible) puedo hacer que este código funcione con referencias? Ejemplo en vivo

Args&&...ystd::forward?Respuestas:
Su problema es que tiene deducciones por conflicto
Argsentre:R (T::*fun)(Args...)Args... argsYo sugeriría que tener un código más genérico (no hay duplicaciones entre
R (T::*fun)(Args...)yversión const
R (T::*fun)(Args...) consty otra alternativa) con:fuente
Argslos tipos no pueden deducirse tanto comoconst&(de lafundeclaración de parámetros) como sin referencia de laargsdeclaración. Una solución simple es usar dos paquetes de parámetros de tipo de plantilla separados:Como inconveniente, puedo imaginar mensajes de error un poco más largos en caso de mal uso.
fuente
Args&&... argsTenga en cuenta que el
Argstipo de parámetro de plantilla se deduce comoconst int&en el argumento de la 3ª función&A::foo, y se deduce comointen el 4º parámetro de la función1. No coinciden y hacen que la deducción falle.Puede excluir el cuarto parámetro de la deducción , p. Ej.
EN VIVO
PS:
std::type_identityes compatible desde C ++ 20; pero es bastante fácil implementar uno.fuente
Args&&..., ponerstd::type_identityel 3er parámetro comoR (T::*fun)(std::type_identity_t<Args>...). EN VIVO y EN VIVO