boost :: any, варианты, вызывающие функции на основе их массивов - PullRequest
1 голос
/ 12 сентября 2010

Учитывая набор функций, таких как: template<class A1> Void Go(A1 a);</p> <p>template<class A1, class A2> Void Go(A1 a1, A2 a2);</p> <p>template<class A1, class A2, class A3> Void Go(A1 a1, A2 a2, A3 a3); Можно ли взять массив некоторого варианта типа и, учитывая его содержимое, запустить правильную функцию?Моя заявка на это заключается в том, что я хочу передать набор параметров X другому процессу, где у меня есть возможность передать только один указатель.Моя идея заключалась в том, чтобы отправить указатель на std :: vectorа затем каким-то образом решить, какой из вышеперечисленных методов запустить с учетом его содержимого.

Это касается моих экспериментов с многопоточными событиями и связью, поэтому это может показаться излишне эзотерическим!

Редактировать: хорошо, например, это намерениеОчевидно, что он не компилируется (разрешение шаблона происходит во время компиляции, но я хочу определить, какую функцию вызывать во время выполнения!):



#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
    }
}

Ответы [ 2 ]

0 голосов
/ 12 сентября 2010

Хорошо, я добился определенного прогресса в этом. Если я использую массив boost :: any, я могу преобразовать в void * и обратно (и, следовательно, передать его как lParam в сообщении пользовательского окна в msgProc). Решение заключается в том, если классы отправителя и получателя имеют одинаковые параметры шаблона. То есть что-то вроде этого (должно скомпилироваться как консольный проект в 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();
}

Выше показано, как перейти от вектора boost :: any к пустоте *, а затем обратно к вектору boost :: any, вызывая функцию для некоторого объекта с правильной арностью и типами.

0 голосов
/ 12 сентября 2010

Да, boost::variant знает тип значения, который в данный момент хранится. Это позволяет посещение и вызовы правильных перегруженных operator(). boost::any использует принципиально другую технику и не может сказать вам, что он в данный момент хранит.

...