2010-09-11 17 views
1

Compte tenu d'un ensemble de fonctions, telles que: boost :: any, variantes, fonctions d'appel basées sur leurs tableaux

 
template<class A1> 
Void Go(A1 a);

template<class A1, class A2> Void Go(A1 a1, A2 a2);

template<class A1, class A2, class A3> Void Go(A1 a1, A2 a2, A3 a3);

Est-il possible de prendre un tableau de type variant et donné son contenu, déclencher la fonction correcte? Mon application pour cela est que je veux passer un ensemble de paramètres X, à un autre processus, où j'ai seulement la possibilité de passer un seul pointeur. Mon idée était d'envoyer un pointeur sur un std :: vector < boost :: any> et ensuite de déterminer d'une façon ou d'une autre quelles sont les méthodes ci-dessus à tirer étant donné son contenu.

Cela concerne mes expériences avec les événements et la communication cross-thread, d'où il peut sembler inutilement ésotérique!

Editer: ok, par exemple, c'est l'intention. De toute évidence, il ne compile pas (la résolution du modèle se produit au moment de la compilation, mais je veux déterminer la fonction à appeler à l'exécution!):



#include <boost\any.hpp> 

#include <vector> 
#include <iostream> 
#include <string> 


class A 
{ 

public: 

    void Go() 
    { 
     std::cout << L"(0 params)\n"; 
    } 

    template 
    void Go(U0 u0) 
    { 
     std::cout << L"1 param " << u0 << L"\n"; 
    } 

    template 
    void Go(U0 u0, U1 u1) 
    { 
     std::cout << L"2 params " << u0 << L" " << u1 << L"\n"; 
    } 

    template 
    void Go(U0 u0, U1 u1, U2 u2) 
    { 
     std::cout << L"3 params " << u0 << L" " << u1 << L" " << u2 << L"\n"; 
    } 

}; 

class B 
{ 

public: 

    void Whatever() {} 

}; 

int main(int argc, wchar_t* argv[]) 
{ 
    // Create a collection of variants. 

    std::vector<boost::any> myVariants; 

    B myB; 

    myVariants.push_back(123); 
    myVariants.push_back(std::wstring(L"Test")); 
    myVariants.push_back(&myB); 



    // Take a void pointer to them. 

    void *variants = &myVariants; 



    // Convert back into an array. 

    std::vector<boost::any>& myConverted = *(std::vector<boost::any> *)(variants); 



    // Fire the correct event on A. 

    A myA; 

    switch(myConverted.size()) 
    { 
    case 0: 
     myA.Go(); 
     break; 

    case 1: 
     myA.Go(myConverted[0]); 
     break; 

    case 2: 
     myA.Go(myConverted[0], myConverted[1]); 
     break; 

    case 3: 
     myA.Go(myConverted[0], myConverted[1], myConverted[2]); 
     break; 

    default: ; 
     // throw 
    } 
} 

Répondre

0

Ok, j'ai fait quelques progrès avec ça. Si j'utilise un tableau de boost :: any, je peux convertir vers et depuis un void * (et donc le passer en tant que lParam dans un message de fenêtre personnalisée à un msgProc). La solution est de savoir si les classes émetteur et récepteur ont les mêmes paramètres de modèle. C'est-à-dire quelque chose comme ça (devrait compiler en tant que projet de la console en 2010):



#include <boost\any.hpp> 

#include <vector> 
#include <iostream> 
#include <string> 

// A class to receive the event. 

template<typename A0 = int, typename A1 = int, typename A2 = int> 
class A 
{ 

public: 

    void Go() 
    { 
     std::wcout << L"(0 params)\n"; 
    } 

    void Go(A0 u0) 
    { 
     std::wcout << L"1 param " << u0 << L"\n"; 
    } 

    void Go(A0 u0, A1 u1) 
    { 
     std::wcout << L"2 params " << u0 << L" " << u1 << L"\n"; 
    } 

    void Go(A0 u0, A1 u1, A2 u2) 
    { 
     std::wcout << L"3 params " << u0 << L" " << u1 << L" " << u2 << L"\n";  
    } 

}; 

// A class to demonstrate passing an abitrary object. 

class B 
{ 

public: 


}; 

// Implement operator on type B so we can use std::cout. 

std::wostream& operator << (std::wostream& o, const B& b) 
{ 
    o << L"Hello!"; 

    return o; 
} 

// A class that converts an array of boost::any from void and calls an appropriate function on A. 

template<typename A0 = int, typename A1 = int, typename A2 = int> 
class C 
{ 

public: 

    void Everything() 
    { 

     // Create a collection of variants. 

     std::vector<boost::any> myVariants; 

     B myB; 

     myVariants.push_back(123); 
     myVariants.push_back(myB); 



     // Take a void pointer to them. 

     void *variants = &myVariants; 



     // Convert back into an array. 

     std::vector<boost::any>& myConverted = *(std::vector<boost::any> *)(variants); 



     // Fire the correct event on A. 

     A<A0, A1, A2> myA; 

     switch(myConverted.size()) 
     { 
     case 0: 
      myA.Go(); 
      break; 

     case 1: 
      myA.Go(boost::any_cast<A0>(myConverted[0])); 
      break; 

     case 2: 
      myA.Go(boost::any_cast<A0>(myConverted[0]), boost::any_cast<A1>(myConverted[1])); 
      break; 

     case 3: 
      myA.Go(boost::any_cast<A0>(myConverted[0]), boost::any_cast<A1>(myConverted[1]), boost::any_cast<A2>(myConverted[2])); 
      break; 

     default: ; 
      // throw 
     } 
    } 
}; 

int main(int argc, wchar_t* argv[]) 
{ 
    C<int, B> c; 

    c.Everything(); 
} 

Ce qui précède démontre passer d'un vecteur de boost :: tout à un vide * et puis de nouveau à un vecteur de boost :: any, appelle une fonction sur un objet avec l'arité et les types corrects.

0

Oui, boost::variant connaît le type de valeur qu'il a actuellement des magasins . Il permet la visite et appelle la surcharge correcte operator(). boost::any utilise une technique fondamentalement différente et ne peut pas vous dire ce qu'il stocke actuellement.

+0

Mais ok, supposons que j'ai un void * à un tableau de telles variantes, que je convertis en std :: vector < boost :: any>. Si le vecteur contient, disons, 3 éléments et que j'appelle "Go (v [0], v [1], v [2]), tout fonctionnera comme prévu, en supposant que leurs types sont corrects par rapport à" Go " instancié dans le modèle? – Robinson

+0

Désolé, dans ce qui précède, je veux dire boost :: variant, pas boost :: any ...! – Robinson

+0

@robinsont non, vous devez utiliser l'interface de visite de celui-ci.Il est expliqué bien mieux que je pouvais faire dans Boostez le manuel de la variante –