我正在为自己编写一个大量使用模板(尤其是可变参数模板)的数学库,并且想实现一个 Sum 仿函数,它可以采用任意数量的不同类型的仿函数并存储它们。我还想避免任何动态内存分配(主要是对我自己的练习,一般来说我并不反对动态内存分配)。
我找不到任何帮助的问题是如何将类实例存储为不同类型。像这样的东西:
any_array<Types...> a = {Type1(), Type2(), Type3(), ...};
通过某种方式遍历 a
为每个值获取正确的类型。使用 boost 不会成为问题,因为我已经在其他地方使用过它。
我提出了一个似乎很有效的解决方案,但我想看看还有哪些其他方法可以解决这个问题。
我对此的解决方案是一个本质上看起来像的类(一个完全编译的实现和示例可以在下面找到):
template <class ... Functions>
class Sum
{
char functions[num_bytes<Functions...>::value];
template <class Next, class ... Others>
void SetFunctions(int offset, Next f, Others ... others)
{
Next * p = (Next*)(functions + offset);
*p = f;
SetFunctions(offset + sizeof(Next), others...);
}
template <class Last>
void SetFunctions(int offset, Last f)
{
Last * p = (Last*)(functions + offset);
*p = f;
}
public:
Sum(Functions ... funcs)
{
SetFunctions(0, funcs...);
}
};
我喜欢这个解决方案,因为它应该很容易推广到我想要的任何类型的累加仿函数,并且下面的实现对用户是隐藏的。我不确定是否将原始字节存储到这些对象中,但我想不出这本身有什么问题。这种被普遍化的可能性让我怀疑它已经在某个地方实现了,但我在自己的搜索中找不到任何东西。
FWIW 这是我实现的完整示例:
#include <functional>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/sizeof.hpp>
#include <boost/mpl/accumulate.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/int.hpp>
#include <iostream>
#include <boost/utility/enable_if.hpp>
using namespace boost::mpl::placeholders;
using namespace boost::mpl;
//Returns the sum of the number of bytes each class takes up.
//This is used as the size of the array we need to create.
template <class ... Args>
struct num_bytes :
boost::mpl::accumulate<vector<Args...>,
int_<0>,
plus<_1, sizeof_<_2> > >::type
{
};
template <class ... Args>
struct empty_list
{
typedef empty_list type;
static const bool value = sizeof...(Args) == 0;
};
template <class ... Functions>
class Sum
{
public:
Sum(Functions ... functions)
{
SetFunctions(0, functions...);
}
inline double operator()(double x)
{
return evaluate<Functions...>(0, x);
}
private:
template <class Next, class ... Others>
inline void SetFunctions(int offset, Next f, Others ... funcs)
{
Next * p = (Next*)(functions + offset);
*p = f;
SetFunctions(offset + sizeof(Next), funcs...);
}
template <class Last>
inline void SetFunctions(int offset, Last f)
{
Last * p = (Last*)(functions + offset);
*p = f;
}
//Because we are not passing our function objects down, we
//have to manually disable this function overload to end the recursive
//instantiations of this function.
template <class Next, class ... Others>
inline double evaluate(int offset, double x,
typename boost::enable_if_c<!empty_list<Others...>::value>::type * dummy = NULL)
{
Next * p = (Next*)(functions + offset);
return evaluate<Others...>(offset + sizeof(Next), x) + (*p)(x);
}
template <class Last>
inline double evaluate(int offset, double x)
{
Last * p = (Last*)(functions+offset);
return (*p)(x);
}
char functions[num_bytes<Functions...>::value];
};
//Function to help initialize a Sum object
template <class ... Functions>
Sum<Functions...> GetSum(Functions ... functions)
{
return Sum<Functions...>(functions...);
}
//return function object of the form f(x) = x + n.
std::binder2nd<std::plus<int> > GetTestFunction(int n)
{
return std::bind2nd(std::plus<int>(), n);
}
int main()
{
auto sum = GetSum(GetTestFunction(0),
GetTestFunction(1),
GetTestFunction(2));
std::cout << sum(0) << ' ' << sum(1) << std::endl;
return 0;
}
运行时输出:3 6
。
注意:我无法使用 gcc-4.6 进行编译,只能使用 gcc-4.7 并且我使用了命令行: g++-4.7 -std=c++0x test_sum.cpp -Wall
最佳答案
在我看来,您需要的是 std::tuple
:
template <class ... Functions>
class Sum
{
std::tuple<Functions...> functions;
public:
Sum(Functions&& ... funcs)
: functions( std::forward< Functions >( funcs )... )
{
}
};
关于c++ - 将实例数组实现为不同类型的好方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15982845/