2012-01-10 2 views
0

J'essaie d'implémenter une version de foncteur de static_cast à utiliser dans std::bind().Functor version de static_cast dans std :: bind()

Je suis au courant de Boost ll_static_cast<K>() (voir using static_cast with boost::bind), mais je n'utilise pas Boost pour le moment.

Il est un exemple de code dans Why do several of the standard operators not have standard functors? mais il ne compilera pas sur GCC 4.2.1:

template <typename Target> 
struct StaticCast 
{ 
    template <typename Source> 
    Target operator()(Source&& source) const 
    { 
     return static_cast<Target>(source); 
    } 
} 

J'ai réussi à obtenir quelque chose à compiler, mais je ne suis pas sûr qu'il est correct:

template <class Target> 
struct StaticCast : public std::unary_function<void, Target> { 
    template <class Source> 
    Target operator()(Source& src) const { 
     return static_cast<Target>(src); 
    } 
}; 

Quelqu'un peut-il me dire si cette version est correcte, et si c'est le cas, pourquoi ai-je besoin de std::unary_function qui n'est pas utilisé dans l'exemple de code précédent?

Utilisation:

std::vector<BaseObject*> vec; // BaseObject* are known to be of type 
    // DerivedObject* of course, please don't ask me how or why... 

std::for_each(vec.begin(), vec.end(), 
    std::bind(&DerivedObject::doStuff, 
     std::bind(StaticCast<DerivedObject*>(), std::placeholders::_1), 
    "with some string")); 
+0

Si vous utilisez 11 C++, mais pas utiliser lambdas? 'std :: for_each (vec.begin(), vec.end(), [] (objet BaseObject *) {static_cast > (obj) -> doStuff();}' – kennytm

+0

Malheureusement, je suis coincé avec GCC 4.2.1 pour le moment, qui ne les supporte pas (j'ai enlevé 'tr1 ::' dans le code pour plus de simplicité) – OlivierB

Répondre

0

Étant donné l'absence de transfert parfait en C++ 03, vous devrez faire en raison des surcharges:

template<class Target> 
struct StaticCast 
{ 
    typedef Target result_type; 

    template<class Source> 
    Target operator()(Source& src) const 
    { 
     return static_cast<Target>(src); 
    } 

    template<class Source> 
    Target operator()(Source const& src) const 
    { 
     return static_cast<Target>(src); 
    } 
}; 

Remarque que je fais explicitement un typedef pour result_type plutôt que d'hériter de std::unary_function<>. La raison en est que le premier paramètre de template à std::unary_function<> est censé être le type d'argument de operator(), mais parce que notre operator() est un template, nous ne pouvons pas le savoir à l'avance, donc il est malhonnête d'en fournir un en premier lieu (en particulier void, ce qui impliquerait que operator() est nul, alors qu'en fait il est unaire).


Aussi, par souci d'exhaustivité, voici le bon C++ 11 version du foncteur:

template<class Target> 
struct StaticCast 
{ 
    template<class Source> 
    Target operator()(Source&& source) const 
    { 
     return static_cast<Target>(std::forward<Source>(source)); 
    } 
} 
0

Une raison pour laquelle le premier ne fonctionne pas est probablement parce que vous utilisez des références rvalue sur un compilateur qui ne prend pas en charge 11 C++.

La raison pour laquelle vous avez besoin de std::unary_function est d'activer std::result_of pour votre classe que std::bind utilise pour en déduire le type de résultat, puisqu'il n'y a pas de decltype en C++ 98.

Si vous regardez std::unary_function vous verrez qu'il définit le type result_type des arguments de modèle que vous passez, ce qui est utilisé par en tourné std::result_of ou std::bind directement.

+0

En fait, même sans références rvalue cela ne fonctionne pas, donc je suppose que la raison est la déduction de la Si je comprends bien, le type peut être déduit automatiquement en C++ 11 et pas en C++ 98? – OlivierB

+0

@OlivierB: C'est pourquoi j'ai écrit ** une ** raison: Oui, les types ne peuvent pas être automatiquement déduits en C++ 98, alors qu'il peut en C++ 11 utiliser 'decltype' – ronag

0

Eh bien, en général votre code est mauvais:

D'abord, vous pouvez avoir des ennuis avec des objets temporaires et r valeurs tout en demandant référence non const pour les

par exemple

float f = StaticCast<float>()(4); 

ne compilera même pas.

Ensuite, vous faites une copie de l'objet pendant la diffusion. Ce n'est peut-être pas ce que vous voulez.

Exemple de source sans que les inconvénients en raison de la sémantique move

+0

Eh bien, je suis d'accord ... Pour ce que je comprends, il n'y a pas une façon parfaite de le faire avec GCC 4.2.1. – OlivierB

Questions connexes