2016-08-08 1 views
3

Est-il possible de lier des arguments à un appel de fonction membre et de lier plus tard l'objet cible séparément? Ce que j'essayais de réaliser est une fonction d'assistance qui reçoit une fonction avec des arguments arbitraires en tant qu'argument, puis l'exécute sur tous les éléments d'une collection.Utilisation de std :: bind pour lier des paramètres et une instance d'objet séparément

void SomeType::Work(UINT a, UINT b, UINT c) 
{ 
    //do something 
} 

template<typename Function, class Container> 
void Execute(const Function& fn, const Container& collection) 
{ 
    for(auto& item : collection) 
    { 
     auto bound = std::bind(fn, &item); 
     bound(); 
    } 
} 

void Test() 
{ 
    //eg. container = vector of SomeType 
    auto fn = std::bind(&Sometype::Work, 10, 20, 30); 
    Execute(fn, container); 
} 

Cela a échoué avec une erreur au sein fonctionnel:

error C2064: term does not evaluate to a function taking 3 arguments 

pointant Finalement à:

see reference to function template instantiation 'void Execute<std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall SomeType::*)(UINT,UINT,UINT),void,SomeType,UINT,UINT,UINT>,UINT &,UINT &,UINT &>>(const Function &)' being compiled 
with 
[ 
    Function=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall SomeType::*)(UINT,UINT,UINT),void,SomeType,UINT,UINT,UINT>,UINT &,UINT &,UINT &> 
] 

Je CONTOURNÉS par juste de passage dans un lambda qui capture les valeurs souhaitées et exécute la fonction désirée sur un objet qui y est passé. Je suis toujours en train de me demander si les fonctions de liaison de cette façon ont des jambes et que j'allais juste mal, ou si ce n'est pas faisable.

+0

où est la définition de 'Sometype :: Work'? –

+0

C'était juste une fonction qui prend les arguments initialement définis. Ajout d'un exemple de définition ci-dessus. – Zepee

+0

Êtes-vous attaché à lier? Je trouve lambda plus clair et moins de bizarreries récursives. – Yakk

Répondre

4

Vous devez laisser un espace réservé pour l'objet cible qui sera lié lors de la deuxième liaison, lors de la liaison de la fonction membre Sometype::Work().

Essayez ceci:

using namespace std::placeholders; 
auto fn = std::bind(&Sometype::Work, _1, 10, 20, 30); 
            ~~ 

LIVE

+0

... BTW :, S'il vous plaît, Comment obtenez-vous cette boîte de fantaisie autour de l'hyperlien 'LIVE'? - Je ne sais pas encore comment faire ça dans mes réponses – WhiZTiM

+0

Intéressant, cela semble prometteur. Je vais donner un coup dans un peu – Zepee

+0

@WhiZ ... mais s'il vous plaît ne faites pas cela. C'est une mauvaise utilisation des balises de formatage. –

0

On dirait que vous voulez simplement appliquer une fonction (avec des arguments spécifiques) à une collection.

Je ne vois pas comment c'est différent d'utiliser std::for_each avec une fonction spécifique.

void Test() 
{ 
    //eg. container = vector of SomeType 
    auto fn1 = [/*whatever*/](const container_value_type& obj) { 
     Sometype::Work(10, 20, 30, obj); 
    } 
    auto fn2 = [/*whatever*/](const container_value_type& obj) { 
     Sometype::Work(40, 50, 60, obj); 
    } 
    std::for_each(container.begin(), container.end(), fn1); 
    std::for_each(container.begin(), container.end(), fn2); 
} 
+0

Seule différence est interface finesse. Ne pas avoir à dupliquer tous les for_each et itérateur begin.end, etc. C'est pourquoi je faisais l'assistant, car il était utilisé dans un tas de fonctions (conteneur qui transfère juste tous les appels vers des objets détenus), sinon j'aurais juste OK for_each ou range basé sur – Zepee

+0

OK, alors pourquoi ne pas utiliser votre 'Execute' mais au lieu d'utiliser std :: bind, utilisez std :: for_each. Je veux dire que vous liez l'élément à la fonction et immédiatement après l'avoir invoqué, alors pourquoi ne pas l'appeler et passer l'élément. IMHO vous le sur-ingénieur ... – ZivS

+0

Ne répond pas à la question –