2010-05-15 13 views
1

Compte tenu de l'objet appelable suivant:Sur reference_wrapper et objets appelables

struct callable : public std::unary_function <void, void> 
{ 
    void 
    operator()() const 
    { 
     std::cout << "hello world" << std::endl; 
    } 
}; 

un std::tr1::reference_wrapper<> appels à travers elle:

callable obj; 
std::tr1::ref(obj)(); 

Au lieu de cela, lorsque le operator() accepte un argument:

struct callable : public std::unary_function <int, void> 
{ 
    void 
    operator()(int n) const 
    { 
     std::cout << n << std::endl; 
    } 
}; 

std::tr1::bind accepte un reference_wrapper comme callable wrapper e ...

callable obj; 
std::tr1::bind(std::tr1::ref(obj), 42)(); 

mais quel est le problème avec ça?

std::tr1::ref(obj)(42); 

g ++ - 4.4 ne peut pas compiler avec l'erreur suivante:

test.cpp:17: error: no match for call to ‘(std::tr1::reference_wrapper<const callable>) (int)’ 
/usr/include/c++/4.4/tr1_impl/functional:462: note: candidates are: typename std::tr1::result_of<typename std::tr1::_Function_to_function_pointer<_Tp, std::tr1::is_function::value>::type(_Args ...)>::type std::tr1::reference_wrapper<_Tp>::operator()(_Args& ...) const [with _Args = int, _Tp = const callable] 

Répondre

0

Tout d'abord, l'utilisation de std :: unary_function pour une fonction null-Ary semble étrange. "unary" = prend un argument. Je ne suis pas sûr que ce soit correct d'utiliser ArgType = void.

Deuxièmement, vous l'avez en arrière. Le premier paramètre de modèle concerne le type d'argument et le second concerne le type de retour. Ainsi, votre objet de fonction unaire doit être définie comme ceci:

struct callable : public std::unary_function<int,void> 
{ 
    void operator()(int n) const 
    { 
     std::cout << n << std::endl; 
    } 
}; 
+0

Je ne vois pas de différence entre le mien et le vôtre.Les arguments template de unary_function sont correctement définis, et void devrait être bon pour operator() (void). En outre, le problème est pour le second ... –

2

Ce que vous assure qu'il ya quelque chose de mal avec elle? Je crois que cela devrait fonctionner:

#include <functional> 
#include <iostream> 

struct callable : public std::unary_function <int, void> 
{ 
    void 
    operator()(int n) const 
    { 
     std::cout << n << std::endl; 
    } 
}; 

int main() {  
    callable obj; 
    std::tr1::ref(obj)(42); 
    return 0; 
} 

au moins avec MS VC++ 9, il compile et exécute très bien, et désinvoltes je ne vois aucune raison, il ne devrait pas travailler avec d'autres compilateurs ainsi. Edit: En regardant TR1, je prends ça en arrière. Cela fonctionne avec VC++ 9, mais je ne pense pas que ce soit vraiment nécessaire de travailler. VC++ 9 ne prend pas en charge les arguments de modèle de variable, ils prennent donc en charge cette surcharge. Assez profondément enterré (<functional> comprend <xawrap>, qui comprend <xawrap0> [qui, à son tour, comprend <xawrap1>]) est le code pour générer une référence et (surtout) la référence aux variantes const pour jusqu'à 10 arguments. C'est presque certainement l'inclusion de la référence aux variantes const qui permet à cela de fonctionner.

+0

Il ne compile pas avec g ++ - 4.3, ni avec g ++ - 4.4 ... –

+0

oui Jerry, la référence const peut être liée à rvalue. En outre, le standard C++ 0x requiert l'implémentation de l'opérateur reference_wrapper() en termes de référence de valeur r. Au lieu de cela, g ++ - 4.4 l'implémente toujours avec l-value ref, même lors de la compilation avec -std = C++ 0x. Donc c'est définitivement un bug (pas vraiment un bug pour C++ 98). –

2

La mise en œuvre de TR1 reference_wrapper de g ++ - 4.4 est équipée de l'opérateur suivant:

template<typename... _Args> 
    typename result_of<_M_func_type(_Args...)>::type 
    operator()(_Args&... __args) const 
    { 
     return __invoke(get(), __args...); 
    } 

Il prend les arguments par référence. D'où l'reference_wrapper ne peut être invoqué passer un argument valeur r:

std::tr1::ref(obj)(42); 

à la place:

int arg = 42; 
std::tr1::ref(obj)(arg); 

fonctionne très bien.

std::tr1::bind(std::tr1::ref(obj), 42)() 

fonctionne parce que bind prend les arguments par copie.