![](/img/trans.png)
[英]What's the most efficient way of declaring a multidimensional array of mixed types?
[英]What's a good way to implement an array of instances to different types
我正在為自己編寫一個大量使用模板(尤其是可變參數模板)的數學庫,並希望實現一個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 )... )
{
}
};
我不知道這是不是一種好方法,但是這是一種方法:
#define BOOST_RESULT_OF_USE_DECLTYPE
#include <functional>
#include <iostream>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/fold.hpp>
#include <boost/phoenix.hpp>
namespace fusion=boost::fusion;
namespace phx=boost::phoenix;
template <class ... Functions>
class Sum
{
public:
Sum(Functions ... functions):functions_(functions...)
{
}
inline double operator()(double x)
{
return fusion::fold(functions_,0,eval(x));
}
private:
template <typename Arg>
struct evaluate
{
evaluate(const Arg& arg):arg_(arg){}
template <typename State, typename Func>
State operator()(State const& current_state, const Func& f)
{
return current_state + f(arg_);
}
Arg arg_;
};
template <typename Arg>
evaluate<Arg> eval(const Arg& arg)
{
return evaluate<Arg>(arg);
}
fusion::vector<Functions...> functions_;
};
//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);
}
struct plus_two
{
double operator()(double arg) const
{
return arg+2;
}
};
int main()
{
auto sum = GetSum(GetTestFunction(0),
phx::arg_names::_1+1,
plus_two());
std::cout << sum(0) << ' ' << sum(1) << std::endl;
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.