将可变参数类型列表解压缩为变量
Unpack variadic type liste to variable
我有一个真正的问题。我尝试提取参数的类型,通过从另一个集合启动来构建参数。所有这些都是为了删除代码的副本。
一些信息:我使用gcc版本4.8.1
所以这是我最小化的代码(有点长,对此感到抱歉):
一个用于序列化某种类型的类(仅使用 int 作为示例)
class Serializer
{
public:
explicit Serializer(unsigned int buffer_size=255) : _cursor_end(0),_cursor_begin(0), _buffer_size(buffer_size)
{
_buffer = new unsigned char[buffer_size];
};
~Serializer(){
delete _buffer;
}
Serializer& operator<<(int i){
push(*reinterpret_cast<uint32_t*>(&i));
return *this;
};
Serializer& operator>>(int& i){
pop(*reinterpret_cast<uint32_t*>(&i));
return *this;
};
protected:
unsigned char* _buffer;
unsigned int _cursor_end;
unsigned int _cursor_begin;
unsigned int _buffer_size;
inline void resize(const unsigned int buffer_cursor_end){
unsigned char* buffer = new unsigned char[buffer_cursor_end];
buffer = (unsigned char*)memcpy(buffer,_buffer,_buffer_size);
delete _buffer;
_buffer = buffer;
_buffer_size = buffer_cursor_end;
};
inline void push(uint32_t& a){
if(_buffer_size < _cursor_end + 4)
resize(_buffer_size+128);
uint8_t *d = (uint8_t *)&a;
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
_buffer[_cursor_end++] = d[0];
_buffer[_cursor_end++] = d[1];
_buffer[_cursor_end++] = d[2];
_buffer[_cursor_end++] = d[3];
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
_buffer[_cursor_end++] = d[3];
_buffer[_cursor_end++] = d[2];
_buffer[_cursor_end++] = d[1];
_buffer[_cursor_end++] = d[0];
#else
#error "byte orden not suported (PDP endian)"
#endif
}
inline void pop(uint32_t& a){
if(_cursor_begin +4 <= _cursor_end)
{
uint8_t *d = (uint8_t *)&a;
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
d[0]= _buffer[_cursor_begin++];
d[1]= _buffer[_cursor_begin++];
d[2]= _buffer[_cursor_begin++];
d[3]= _buffer[_cursor_begin++];
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
d[3]= _buffer[_cursor_begin++];
d[2]= _buffer[_cursor_begin++];
d[1]= _buffer[_cursor_begin++];
d[0]= _buffer[_cursor_begin++];
#else
#error "byte orden not suported (PDP endian)"
#endif
}
};
};
现在 2 个愚蠢的测试函数
int getVersion(Serializer& sock)
{
return 42;
}
int testParamInt(Serializer& sock,int v)
{
std::cout<<"param:"<<v<<std::endl;
return v+12;
}
称呼他们:
int main(int argc, char* argv[])
{
{
Serializer params;
std::cout<<"getVersion : "<<getVersion(params)<<std::endl;;
}
{
Serializer params;
params<<42;
int p1;
params>>p1;
std::cout<<"testParamInt: "<<testParamInt(params,p1)<<std::endl;
}
return 0;
}
输出:
getVersion : 42
param:42
testParamInt: 54
好的,暂时没有探测。现在我尝试将函数的调用更改为类似的东西(结果相同)
int main(int argc, char* argv[])
{
{
Serializer params;
std::cout<<"getVersion : "<<exec(getVersion,params)<<std::endl;;
}
{
Serializer params;
params<<42;
std::cout<<"testParamInt: "<<exec(testParamInt,params)<<std::endl;
}
return 0;
};
所以我创造了一些治疗师:
#include <tuple>
template<int...> struct index_tuple{};
template<int I, typename IndexTuple, typename... Types>
struct make_indexes_impl;
template<int I, int... Indexes, typename T, typename ... Types>
struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...>
{
typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type;
};
template<int I, int... Indexes>
struct make_indexes_impl<I, index_tuple<Indexes...> >
{
typedef index_tuple<Indexes...> type;
};
template<typename ... Types>
struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...>{};
// ----------UNPACK TUPLE AND APPLY TO FUNCTION ---------
template<class Ret, class... Args, int... Indexes>
Ret apply_helper( Ret (*pf)(Serializer&,Args...),Serializer& sock, index_tuple< Indexes... >, std::tuple<Args...>&& tup)
{
{sock>>std::get<Indexes>(tup)...};
return pf(sock,std::forward<Args>(std::get<Indexes>(tup))...);
};
template<typename Ret,typename ... Args>
Ret apply(Ret (*pf)(Serializer&,Args...),Serializer& sock,const std::tuple<Args...>& tup)
{
return apply_helper(pf,sock,typename make_indexes<Args...>::type(), std::tuple<Args...>(tup));
};
template<typename Ret,typename ... Args>
Ret exec(Ret(*pf)(Serializer&,Args ...),Serializer& sock)
{
std::tuple<Args ...> params;
return apply(pf,sock,params);
}
但是这一行不编译
{sock>>std::get<Indexes>(tup)...};
错误信息
test.cpp: In function ‘Ret apply_helper(Ret (*)(Serializer&, Args ...), Serializer&, index_tuple<Indexes ...>, std::tuple<_Elements ...>&&)’:
test.cpp:129:34: error: expected ‘;’ before ‘...’ token
{sock>>std::get<Indexes>(tup)...};
^
test.cpp:129:34: error: parameter packs not expanded with ‘...’:
这条线的目的是获得论证者的价值。所以我用它改变了它:
const Serializer& c{sock>>std::get<Indexes>(tup)...};
现在它被接受,但我在运行时有一个很大的错误,输出:
getVersion : 42
param:42
testParamInt: 54
*** Error in `/media/HDD1/DEV/test': double free or corruption (top): 0x0000000000603010 ***
======= Backtrace: =========
...
*** Error in `./test': double free or corruption (top): 0x00000000007b8010 ***
使用 gdb,告诉我它崩溃了:序列化器::~序列化程序
现在问题来了,你能帮我吗?
编辑:解决方案
#include <tuple>
#include <type_traits>
template<int...> struct index_tuple{};
template<int I, typename IndexTuple, typename... Types>
struct make_indexes_impl;
template<int I, int... Indexes, typename T, typename ... Types>
struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...>
{
typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type;
};
template<int I, int... Indexes>
struct make_indexes_impl<I, index_tuple<Indexes...> >
{
typedef index_tuple<Indexes...> type;
};
template<typename ... Types>
struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...>
{};
// ----------UNPACK TUPLE AND APPLY TO FUNCTION ---------
//
template<class Ret, class... Args, int... Indexes>
Ret exec__( Ret (*pf)(Serializer&,Args...),Serializer& sock, index_tuple< Indexes... >, std::tuple<Args...>&& args)
{
int ctx[] = { ((sock >> std::get<Indexes>(args)), void(), 0)... };
(void)ctx;
return pf(sock,std::forward<Args>(std::get<Indexes>(args))...);
};
template<typename Ret,typename ... Args>
Ret exec(Ret(*pf)(Serializer&,Args ...),Serializer& sock)
{
return exec__(pf,sock,typename make_indexes<Args...>::type(), std::tuple<typename std::remove_reference<Args>::type...>());
}
这应该可以解决问题:
template<typename T, T...>
struct integer_sequence
{ };
template<std::size_t... Indices>
struct indices : integer_sequence<std::size_t, Indices...>
{ };
template<std::size_t N, std::size_t... T>
struct build_indices : build_indices<(N - 1), (N - 1), T...>
{ };
template<std::size_t... T>
struct build_indices<0, T...> : indices<T...>
{ };
template<typename Fn, typename... Args, std::size_t... Idx>
auto exec__(Fn fn, Serializer& ser, std::tuple<Args...> args, indices<Idx...>)
-> decltype(fn(ser, std::get<Idx>(args)...))
{
int ctx[] = { ((ser >> std::get<Idx>(args)), void(), 0)... };
(void)ctx;
return fn(ser, std::get<Idx>(args)...);
}
template<typename R, typename... Args>
auto exec(R(*fn)(Serializer&, Args...), Serializer& ser)
-> decltype(fn(ser, Args()...))
{
return exec__(fn, ser, std::tuple<typename std::remove_reference<Args>::type...>(), build_indices<sizeof...(Args)>());
}
关于 ideone 的现场示例
相关文章:
- 使用C++进行运行长度解压缩
- C++ 如何将数组值解压缩为函数参数
- struct.error:解压缩 C++ 结构时,解包需要 288 字节的缓冲区
- 在 Qt(C++) 中使用 QProcess 解压缩 - 提取目录问题
- 浏览压缩文件与游览解压缩它们
- 如何在C++向量中解压缩多个值
- 解压缩 C 样式数组以及C++中的参数包
- 如何在 cpp 中解压缩数字,如果它们是使用 struct.pack(fmt, v1, v2, ..) 打包在 pyth
- 如何使用 Poco::ZIP 压缩/解压缩 zip 文件
- 在编译时解压缩数组扩展数据块 (C++11/14)
- 使用 RtMidi 解压缩 Midi 时间码
- 将参数包解压缩到 std::initializer_list?
- 解压缩可变模板参数
- 解压缩附加的压缩字符串
- 使用 AVX2 将 8 位从 32 位值 (__m256i) 解压缩到__m256的最快方法
- C++宏解压缩并加入
- 解压缩串联的 zlib 流而不读取下一个字节
- 解压缩位大小不能被 8 整除的值流
- 为流运算符返回代理类时解压缩参数
- 如何在 Node.js 中解压缩 c# 打包结构