web-dev-qa-db-fra.com

pointeur de fonction membre générique comme paramètre de modèle

Considérez ce code:

#include <iostream>
using namespace std;

class hello{
public:
    void f(){
        cout<<"f"<<endl;
    }
    virtual void ff(){
        cout<<"ff"<<endl;
    }
};

#define call_mem_fn(object, ptr)  ((object).*(ptr))

template<R (C::*ptr_to_mem)(Args...)> void proxycall(C& obj){
    cout<<"hello"<<endl;
    call_mem_fn(obj, ptr_to_mem)();
}

int main(){
    hello obj;
    proxycall<&hello::f>(obj);
}

Bien sûr, cela ne se compilera pas à la ligne 16, car le compilateur ne sait pas ce que sont R, C et Args. Mais il y a un autre problème: si l'on essaie de définir ces paramètres de modèle juste avant ptr_to_mem, il se retrouve dans cette mauvaise situation:

template<typename R, typename C, typename... Args, R (C::*ptr_to_mem)(Args...)> 
                             //  ^variadic template, but not as last parameter!
void proxycall(C& obj){
    cout<<"hello"<<endl;
    call_mem_fn(obj, ptr_to_mem)();
}

int main(){
    hello obj;
    proxycall<void, hello, &hello::f>(obj);
}

Étonnamment, g ++ ne se plaint pas que Args n'est pas le dernier paramètre de la liste des modèles, mais de toute façon il ne peut pas lier proxycall à la bonne fonction de modèle, et note simplement que c'est un candidat possible.

Toute solution? Mon dernier recours est de passer le pointeur de la fonction membre comme argument, mais si je pouvais le passer en tant que paramètre de modèle, il conviendrait mieux au reste de mon code.

EDIT: comme certains l'ont souligné, l'exemple semble inutile parce que proxycall ne passera aucun argument. Ce n'est pas vrai dans le code sur lequel je travaille: les arguments sont récupérés avec quelques astuces de modèle à partir d'une pile Lua. Mais cette partie du code n'est pas pertinente pour la question, et plutôt longue, donc je ne la collerai pas ici.

27
Lorenzo Pistone

Vous pouvez essayer quelque chose comme ceci:

template <typename T, typename R, typename ...Args>
R proxycall(T & obj, R (T::*mf)(Args...), Args &&... args)
{
    return (obj.*mf)(std::forward<Args>(args)...);
}

Utilisation: proxycall(obj, &hello::f);

Alternativement, pour faire du PTMF un argument de modèle, essayez la spécialisation:

template <typename T, T> struct proxy;

template <typename T, typename R, typename ...Args, R (T::*mf)(Args...)>
struct proxy<R (T::*)(Args...), mf>
{
    static R call(T & obj, Args &&... args)
    {
        return (obj.*mf)(std::forward<Args>(args)...);
    }
};

Usage:

hello obj;

proxy<void(hello::*)(), &hello::f>::call(obj);

// or

typedef proxy<void(hello::*)(), &hello::f> hello_proxy;
hello_proxy::call(obj);
36
Kerrek SB