gpt4 book ai didi

c++ - 不同仿函数的容器

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:38:54 25 4
gpt4 key购买 nike

我正在尝试找出一种方法来拥有一个仿函数容器,以便我可以将一个值传递给仿函数并对其进行修改,但是我无法让仿函数不受限于它们可以是什么类型通过以及他们可以接受的参数数量。

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

我完成这项工作的唯一方法是继承和一堆空指针,这使得代码极难遵循、调试和使用。

到目前为止,这是我的代码,希望能够证明我正在尝试做的比上面输入的更好。请注意,我已经完全脱离了我的舒适区,所以这段代码可能很可怕,让你们中的一些专家想用棍子打我。

#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

最佳答案

您是否考虑过使用 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;
}

关于c++ - 不同仿函数的容器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8581902/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com