Dernièrement, j'ai écrit une fonction de modèle pour résoudre certaines répétitions de code. Cela ressemble à ceci:
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);
}
Ce code fonctionne parfaitement bien pour class A
ce qui ressemble à ceci:
class A {
public:
void foo(int x) {
}
};
Mais ne parvient pas à compiler pour celui-ci:
class A {
public:
void foo(const int& x) {
}
};
Pourquoi en est-il ainsi (par pourquoi je veux dire pourquoi il ne parvient pas à déduire le type) et comment (si c'est possible) pour faire fonctionner ce code avec des références? Exemple en direct
Args&&...
- être etstd::forward
?Réponses:
Votre problème est que vous avez des déductions de conflit
Args
entre:R (T::*fun)(Args...)
Args... args
Je suggère d'avoir un code plus générique (pas de duplication entre
R (T::*fun)(Args...)
et laversion const
R (T::*fun)(Args...) const
et autre alternative) avec:la source
Args
les types ne peuvent pas être déduits à la fois commeconst&
(de lafun
déclaration de paramètre) et non-référence de laargs
déclaration. Une solution simple consiste à utiliser deux packs de paramètres de type de modèle distincts:Comme inconvénient, je peux imaginer des messages d'erreur légèrement plus longs en cas de mauvaise utilisation.
la source
Args&&... args
Notez que le type du paramètre
Args
de modèle est déduit commeconst int&
sur le troisième argument de fonction&A::foo
et déduit commeint
sur le quatrième paramètre de fonction1
. Ils ne correspondent pas et la déduction échoue.Vous pouvez exclure le 4ème paramètre de la déduction , par exemple
VIVRE
PS:
std::type_identity
est pris en charge depuis C ++ 20; mais il est assez facile d'en implémenter un.la source
Args&&...
-à- dire , puis mettrestd::type_identity
le 3ème paramètre commeR (T::*fun)(std::type_identity_t<Args>...)
.