将variadic类型列表解压缩到变量

时间:2013-10-16 17:40:17

标签: c++ c++11 variadic-templates unpack

我有一个真正的问题。我尝试通过从另一个agrument引导来提取函数的类型以构建参数。 所有这些都是为了删除代码的副本。

一些形象:我使用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;
};

所以我创造了一些healper:

#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,让我崩溃:Serializer :: ~Serializer

现在描述了问题,你能帮助我吗?


编辑:解决方案

#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...>());
}

1 个答案:

答案 0 :(得分:3)

这应该可以解决问题:

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

上的实例
相关问题