2010-11-03 23 views
3

Supposons que j'ai une fonction qui prend un foncteur arité comme argument:Perform substitution des arguments sur la poussée imbriqué :: bind sans composition

void enqueue(boost::function<void()> & functor); 

J'ai une autre fonction qui prend un entier et fait quelque chose en interne:

void foo(int a); 

Je voudrais nid, mais pas composer, ceux-ci ensemble pour que je sois un foncteur avec la signature:

boost::function<void(int)> functor 

qui, lorsqu'il est appelé avec une valeur - dire 4 - effectue les opérations suivantes:

enqueue(boost::bind(&foo, 4)) 

Ma première tentative a été la suivante:

boost::function<void(int)> functor = boost::bind(&enqueue, boost::bind(&foo,_1)) 

Cela échoue parce que bind exécute la composition lorsqu'elle est administrée une liaison imbriquée. foo a d'abord été appelé, puis la valeur void a été "retournée" à enqueue, ce qui échoue.

Ma deuxième tentative a été la suivante:

boost::function<void(int)> functor = boost::bind(&enqueue, boost::protect(boost::bind(&foo, _1))) 

Cela a échoué car enqueue accepte un foncteur arité, non unaire.

Est-ce que ce que je cherche peut être fait?

Autres informations:

  • Ceci est essentiellement identique à la question sans réponse du forum coup de pouce il y a 6 ans: http://lists.boost.org/boost-users/2004/07/7125.php
  • Un peu de lecture suggère que l'utilisation de boost :: lambda :: bind avec boost :: lambda :: unlambda et boost :: lambda :: protect peut faire ce que je cherche. Malheureusement, boost :: lambda a un nombre inacceptable d'espaces réservés autorisés (3), et un temps de compilation élevé.
+0

en plus de l'emboîtement manuel suggéré ci-dessous, cela devrait d travail: –

Répondre

4

Question intéressante ...

Ce que vous voulez est essentiellement un "appel lié à lier". De la même manière que lier un appel à foo(x, y) est écrit bind(&foo, x, y), lier un appel à bind(&foo, x) devrait être comme bind(&bind, &foo, x). Toutefois, en prenant l'adresse d'une fonction surchargée devient rapidement laid et, comme boost::bind a plus que je ne pouvais surcharge compter, il devient assez laid:

// One single line, broken for "readability" 
boost::function<void(int)> f = boost::bind(
    &enqueue, 
    boost::bind(
    static_cast< 
     boost::_bi::bind_t< 
     void, void(*)(int), boost::_bi::list_av_1<int>::type 
     > 
     (*)(void(*)(int), int) 
    >(&boost::bind), 
    &foo, 
    _1 
) 
); 

Vous serez probablement d'accord que, bien que « intéressant », ci-dessus ne gagnera pas de concours de lisibilité.La séparation de l'obtention de la surcharge de liaison correcte du reste rend les choses un peu plus facile à gérer:

boost::_bi::bind_t<void, void(*)(int), boost::_bi::list_av_1<int>::type> 
    (*bind_foo)(void(*)(int), int) = &boost::bind; 

boost::function<void(int)> q = boost::bind(&enqueue, boost::bind(bind_foo, &foo, _1)); 

mais je hésite encore à le recommander;)

Edit:

Répondre Commentaire de l'OP à propos de comment/si C++ 0x aiderait à nettoyer la syntaxe: Il fait:

auto f = [](int i){enqueue([=](){foo(i);});}; 
+0

Incroyable. Je pense que même si boost est très pratique, il n'a pas été conçu pour être utilisé à ce niveau "méta". Par exemple, j'ai essayé d'obtenir le type de chaque élément d'un tuple (si je me souviens bien, le type retourné par un get <0>(), par exemple) et je ne pouvais pas. J'ai réalisé qu'il utilisait un type 'detail ::' interne. Pour offrir un vrai niveau de méta-programmation, ces types devraient avoir été rendus accessibles (même chose que 'value_type' dans les cartes, disons). –

+0

@Diego Sevilla: Je ne suis que partiellement d'accord. Pour votre exemple de tuple, les métafonctions sont fournies. Voir 'element :: type' dans http://www.boost.org/doc/libs/1_44_0/libs/tuple/doc/tuple_advanced_interface.html –

+0

Ahh, vivez pour apprendre. Zut! J'ai raté cette partie. Vraiment merci pour le pointeur! –

0

'Nest' manuellement:

class Enqueuer { 
std::function<void (int)> mFunc; 

public: 
void operator()(int pVal) { 
    enqueue(std::bind(mFunc, pVal)); 
} 

Enqueuer(std::function<void (int)> pFunc) 
    : mFunc(pFunc) {} 
}; 

// usage: 
Enqueuer e(foo); 
e(1); 
e(2); 
e(3);