容器的不同的玩具

时间:2011-12-20 20:59:18

标签: c++ containers void-pointers

我试图找出一种方法来容纳一个仿函数容器,这样我就可以将一个值传递给仿函数并对它进行修改但是我很难让仿函数不受限制它们可以是什么类型通过了他们可以采取的论据数量。

我的实际用途是我有一系列的仿函数,它们都会根据输入以某种方式改变3D矢量。通过能够将这些仿函数存储在容器中,我可以操纵它们被调用的顺序,并通过遍历容器传递每个仿函数向量来结束不同的结果向量。我正在使用这些向量来确定粒子的位置,颜色,加速度等。因此,最终我可以通过采用这种模块化方法创建截然不同的粒子效果,最终我可以在运行时通过文件定义仿函数顺序。这是我的最终目标:)

我完成这项工作的唯一方法是使用继承和一堆void指针,这使得代码非常难以跟踪,调试和使用。

到目前为止,这是我的代码,希望能够证明我所做的比我上面输入的更好。请注意,我高度偏离了我的舒适区,所以这段代码可能很糟糕,让你们中的一些大师想用棍子打我。

#include <iostream>
#include <vector>

//the base functor class
struct Functor {
    //an integer so we can tell how many arguments the functor takes
    unsigned num_arguments;
    Functor() : num_arguments(0) {}

    //I'm making the arguments default to 0 so the compiler doesn't complain about not giving enough arguments
    virtual void operator()(void* R, void* A1 = 0, void* A2 = 0, void* A3 = 0) = 0;
};

template<typename R, typename A1>
struct Double : public Functor {
    Double() { num_arguments = 1; }
    void operator()(void* i, void* a, void*, void*) {
        //having to cast everything out of void pointers so it can be used
        A1& first = *static_cast<A1*>(a);

        *static_cast<R*>(i) = first * 2;
    }
};

template<typename R, typename A1, typename A2>
struct Sub : public Functor {
    Sub() { num_arguments = 2; }
    void operator()(void* i, void* a, void* b, void*) {
        //having to cast everything out of void pointers so it can be used
        A1& first = *static_cast<A1*>(a);
        A2& second = *static_cast<A2*>(b);

        *static_cast<R*>(i) = first - second;
    }
};

int main() {
    //our container for the functors
    std::vector<Functor*> functors;
    functors.push_back(new Double<int, int>);
    functors.push_back(new Sub<int, int, int>);

    for(int i = 0; i < functors.size(); ++i) {
        int result;
        int first = 1, second = 2;
        Functor& f = *functors[i];

        if(f.num_arguments == 1) {
            f(&result, &first);
        } else if(f.num_arguments == 2){
            f(&result, &first, &second);
        }

        std::cout << result << std::endl;
    }

    Functor* float_sub = new Sub<float, float, float>;
    float result;
    float first = 0.5f, second = 2.0f;
    (*float_sub)(&result, &first, &second);
    std::cout << result << std::endl;

    functors.push_back(float_sub);

    //The functors vector now contains 3 different types of functors:
    //One that doubles an integer
    //One that subtracts two integers
    //One that subtracts two floats

    std::cin.get();
    return 0;
}

旁注: 我期待有些人告诉我使用boost库中的某某某某。虽然我很高兴知道这个选项在那里我仍然想知道一个更好的方法来实现这个没有任何外部库,因为这是我自己的学习练习。

修改

好的,所以我已经了解了stdargboost::any我认为我可以看到一种方法可以很好地完成这项工作并尝试一下:)


解决方案2

好的,我已经使用boost::anycstdarg重新编写了代码,我认为这是一个更好的解决方案。这不使用void指针,也不限制仿函数可以拥有的参数数量。较新的代码还允许您通过值传入,使用void指针,所有必须通过引用,这将导致尝试执行的问题:Sub(&result, 1, 1)

#include <iostream>
#include <vector>
#include <cstdarg>
#include <boost\any.hpp>

struct Functor {
    unsigned num_arguments;
    Functor() : num_arguments(0) {}

    virtual void operator()(boost::any, ...) = 0;
};

template<typename R, typename A1>
struct Double : public Functor {
    Double() { num_arguments = 1; }
    void operator()(boost::any r, ...) {
        R* out = boost::any_cast<R*>(r);

        va_list args;
        va_start(args, r);
        A1 first = va_arg(args, A1);
        va_end(args);

        *out = first * 2;
    }
};

template<typename R, typename A1, typename A2>
struct Sub : public Functor {
    Sub() { num_arguments = 2; }
    void operator()(boost::any r, ...) {
        R* out = boost::any_cast<R*>(r);

        va_list args;
        va_start(args, r);
        A1 first = va_arg(args, A1);
        A2 second = va_arg(args, A2);
        va_end(args);

        *out = first - second;
    }
};

int main() {
    std::vector<Functor*> functors;

    functors.push_back(new Double<int, int>);
    functors.push_back(new Sub<int, int, int>);
    functors.push_back(new Sub<int, float, float>);

    int result = 0;

    for(int i = 0; i < functors.size(); ++i) {
        (*functors[i])(&result, 2, 2);
        std::cout << result << std::endl;
    }

    std::cin.get();
    return 0;
}

现在我终于有幸投票:D

2 个答案:

答案 0 :(得分:4)

您是否考虑过使用variadic argument lists from the stdarg library?我不确定它是更好的解决方案,但它是不同的。例如:

#include <vector>
#include <cstdarg>
#include <iostream>

using namespace std;

template< typename type >
void sub( void* out, ... ){
    // Initialize the variadic argument list.
    va_list args;
    va_start( args, out );

    // Extract our arguments.
    type lhs = va_arg( args, type );
    type rhs = va_arg( args, type );

    // Close the variadic argument list.
    va_end( args );

    // Function logic goes here.
    *(static_cast<type*>(out)) = lhs - rhs;
}

int main( void ){
    typedef void (*functor)( void* out, ... );  // Function type.
    typedef vector< functor > FunctorList;      // Function list type.

    FunctorList fList;
    fList.push_back( &sub<int> );

    int diff;
    fList[0]( &diff, 3, 5 );
    cout << diff << endl;

    return 0;
}

答案 1 :(得分:2)

我没有意识到你特意想要的功能对象(应该点击你使用的“functor”而不是“函数指针”)。无论如何,这是我之前使用函数对象的答案。它的工作原理相同:

#include <vector>
#include <cstdarg>
#include <iostream>

using namespace std;

struct FunctorBase {
    virtual void operator()( void* out, ... ) = 0;
}; // end FunctorBase

template< typename T >
struct Subtract : public FunctorBase {
    void operator()( void* out, ... ){
        // Initialize the variadic argument list.
        va_list args;
        va_start( args, out );

        // Extract our arguments
        T lhs = va_arg( args, T );
        T rhs = va_arg( args, T );

        // Close the variadic argument list.
        va_end( args );

        // Function logic goes here.
        *(static_cast<T*>(out)) = lhs - rhs;
    }
};

int main( void ){
    typedef vector< FunctorBase* > FunctorList; // Function list type.

    FunctorList fList;
    fList.push_back( new Subtract<int>() );

    int diff;
    (*fList[0])( &diff, 3, 5 );
    cout << diff << endl;

    return 0;
}