这种自动化的转换不仅仅大大降低了转换的复杂度还解决了手工拷贝的时候容易出错的问题,程序自动化的拷贝保证了拷贝的正确性。目前我还没看到有类似的转换类或者函数能够自动地很方便地将复杂结构体转换为char数组,想想自己实现一个也不是难事,其实要实现自动转换最关键的是要获取结构体的元信息,有了元信息我们就能对结构体中的每个字段进行转换了。在c#中可以通过反射很方便的获取结构体的元信息,而c++中没有反射,就要想其它办法来获取元信息了。而且这个获取元信息的方法还要非常简单,几乎不增加额外的负担。这里我是通过tuple来获取原信息,要求每个结构体要定义一个Get方法来返回其字段的基本信息,比如:
struct A
{
int x;
double y;
auto Get()->decltype(std::make_tuple(x,y))
{
return std::make_tuple(x,y);
}
};
这个Get方法非常简单,只要将字段放到tuple中返回出去就行了,几乎没有增加额外的负担,这个看似简单函数却有着巨大的作用,只要有这个Get函数我就可以获取结构体的基本元信息了,有了这个以后,所有的转换都可以实现自动化了。还是来看看具体是如何实现自动化的转换吧:
#include
#include
#include
namespace Cosmos
{
namespace Detail
{
struct Functor
{
Functor(char* buf, int len) :m_buf(buf), m_bufLen(len)
{
}
template
typename std::enable_if::value>::type operator()(T t)
{
FillForward(t);
}
template
typename std::enable_if< xml:namespace prefix = std />::value>::type operator()(T& t)
{
FillForward(t);
}
private:
template
void FillForward(T&& t)
{
if (std::is_same::value || std::is_same::value)
m_latestInt = t;
FillIn(std::forward(t), m_buf + m_curPos);
m_curPos += sizeof(T);
}
template
typename std::enable_if::value>::type FillIn(T t, char* p)
{
*((T*) p) = t;
}
template
typename std::enable_if::value>::type FillIn(T t, char* p)
{
if(std::is_same::value)
sprintf(p, "%.15f", t);
else
sprintf(p, "%f", t);
}
template
typename std::enable_if::value&&std::is_class::type>::value>::type FillIn(T t,
char* p)
{
Fill(t, p, [this, &t](int i, char* p, int size){Put(p + i*size, size, t[i]); });
}
template
typename std::enable_if::value&&std::is_arithmetic::type>::value>::type FillIn(T
t, char* p)
{
Fill(t, p, [this, &t](int i, char* p, int size){FillIn(t[i], p + i*size); });
}
template
void Fill(T t, char* p, F&& f)
{
int count = m_latestInt.AnyCast();
using U = typename std::remove_pointer::type;
for (int i = 0; i < count; i++)
{
f(i, p, sizeof(U));
}
}
template
typename std::enable_if::value&&std::is_void::type>::value>::type FillIn(T t,
char* p)
{
int count = m_latestInt.AnyCast();
int* temp = (int*) t;
for (int i = 0; i < count; i++)
{
FillIn(temp[i], p + i*sizeof(int));
}
}
template
typename std::enable_if::value>::type FillIn(T& t, char* p)
{
strcpy(p, t.c_str());
}
template
typename std::enable_if::value&&!std::is_same::value>::type FillIn(T& t, char* p)
{
Put(p, sizeof(T), t);
}
char* m_buf;
int m_bufLen;
int m_curPos = 0;
Any m_latestInt = 0;
};
template
void for_each_impl(Func&& f, Last&& last)
{
f(last);
}
template
void for_each_impl(Func&& f, First&& first, Rest&&...rest)
{
f(first);
for_each_impl(std::forward(f), rest...);
}
template
void for_each_helper(Func&& f, IndexTuple, std::tuple&& tup)
{
for_each_impl(std::forward(f), std::forward(std::get(tup))...);
}
}
template
void tp_for_each(Func&& f, std::tuple& tup)
{
using namespace details;
for_each_helper(forward(f), typename make_indexes::type(), std::tuple(tup));
}
template
void tp_for_each(Func&& f, std::tuple&& tup)
{
using namespace details;
for_each_helper(forward(f), typename make_indexes::type(), forward>(tup));
}
template
void Put(char* p, int len, T&& t)
{
using namespace Detail;
tp_for_each(Functor(p, len), t.Get());
}
}
View Code
代码中用到了Any,这个Any就是我前面的博文中实现的Any,想查看可以点这里。