2011-07-04 1 views
2

J'ai une fonction C++ très polymorphe qui peut être appelée avec près de 20 types différents.Une manière intelligente d'exporter des fonctions polymorphes C++ avec boost.python

Pour l'exposer à python que je fais quelque chose comme ceci:

#include originalFunctionNamespace.hpp 

template<class T> 
    T foo(T x) 
    { 
     return orignalFunctionNamespace::foo(x); 
    } 

mais de les appeler de python je dois spécialiser les fonctions avec chaque type qu'ils soutiennent:

BOOST_PYTHON_MODULE(module_foo) 
{ 
    def("foo", foo<orignalFunctionNamespace::type1>); 
    def("foo", foo<orignalFunctionNamespace::type2>); 
    def("foo", foo<orignalFunctionNamespace::type3>); 
    def("foo", foo<orignalFunctionNamespace::type4>); 
    def("foo", foo<orignalFunctionNamespace::type5>); 
    def("foo", foo<orignalFunctionNamespace::type6>); 
    def("foo", foo<orignalFunctionNamespace::type7>); 
    ... 
    ... 
    ... 
    def("foo", foo<orignalFunctionNamespace::typeN>); 
} 

Cela fonctionne, mais je ne peux m'empêcher de penser qu'il doit y avoir une façon plus intelligente de le faire. Comme je dois le faire pour de nombreuses fonctions, les choses deviennent de plus en plus grandes et répétitives. Des suggestions?

+1

Cela ne semble pas être un polymorphisme, mais simplement une surcharge de fonction. – interjay

+1

Pas vraiment un meilleur moyen mais vous pourriez essayer d'utiliser le préprocesseur pour raccourcir chaque ligne et "using namespace originalFunctionNamespace;" pour les raccourcir davantage. Que deos ne résout pas la répétition mais au moins vous sauve beaucoup de texte. – Nobody

+0

@interjay la fonction peut recevoir plusieurs types en entrée et sortira de nombreux types différents en conséquence. "Une fonction qui peut évaluer ou être appliquée à des valeurs de différents types est connue comme une fonction polymorphe." droite? –

Répondre

0

Cela me semble être une utilisation possible de la magie typeliste.

Si vous utilisez (ou peut utiliser) le nouveau standard C++ 0x, vous pouvez écrire quelque chose comme ceci:

template <typename ArgType> 
void def_foo_overloads() 
{ 
    def("foo", foo<ArgType>); 
    // last type in list 
} 
template <typename ArgType, typename... MoreArgTypes> 
void def_foo_overloads() 
{ 
    def("foo", foo<ArgType>); 
    def_foo_overloads(MoreArgTypes...); 
} 

// use it like: 
def_foo_overloads<orignalFunctionNamespace::type1, 
        orignalFunctionNamespace::type2, 
        ... 
        orignalFunctionNamespace::typeN>(); 

Si vous n'avez pas accès à la nouvelle norme, vous pouvez faites l'équivalent en utilisant les anciennes typologies récursives.

+0

ou: 'template void def_overloads() {std :: initializer_list {(def (" foo ", foo ), void(), 0) ...}; } ' –

+0

C'est très bien! – Useless

+1

Ce n'est pas spécifique à 'std :: initializer_list ' non plus. Chaque construction qui utilise la nouvelle syntaxe d'initialisation de liste garantit l'ordre d'évaluation de ses paramètres, même si cela équivaut par exemple à un appel de constructeur (où la seule garantie est le point de séquence avant d'entrer dans le corps du constructeur, comme d'habitude). Ainsi, par exemple 'std :: pair (++ i, ++ i)' est mauvais alors que 'std :: pair {++ i, ++ i}' est correct. 'std :: initializer' est utilisé ici parce qu'il peut accepter un nombre arbitraire d'arguments. J'utilise personnellement un type vide avec un constructeur variadique. –

Questions connexes