我有一段代码,我试图在给定等待的数据类型的情况下自动解码缓冲区。数据用元组表示:
std::tuple<uint8_t, int32_t> data;
size_t bufferIndex;
IOBuffer::ConstSPtr buffer( std::make_shared<IOBuffer>(5) );
我也有元组帮助器来迭代元组,并为每个元组执行一个函函数:
//-------------------------------------------------------------------------
//
template <typename Function, typename ...Tuples, typename ...Args>
void IterateOverTuple( Function& f, std::tuple<Tuples...>& t,
Args&... args )
{
impl::IterateOverTupleImpl<0, sizeof...(Tuples),
std::tuple<Tuples...>>()( f, t, args... );
}
//---------------------------------------------------------------------
//
template <int I, size_t TSize, typename Tuple>
struct IterateOverTupleImpl
: public IterateOverTupleImpl<I + 1, TSize, Tuple>
{
template <typename Function, typename ...Args>
void operator()( Function& f, Tuple& t, Args&... args )
{
f( std::get<I>(t), args... );
IterateOverTupleImpl<I + 1, TSize, Tuple>::operator()( f, t,
args... );
}
};
//---------------------------------------------------------------------
//
template <int I, typename Tuple>
struct IterateOverTupleImpl<I, I, Tuple>
{
template <typename Function, typename ...Args>
void operator()( Function& f, Tuple& t, Args&... )
{
cl::Ignore(f);
cl::Ignore(t);
}
};
这是我的解码器函子
struct DecoderFunctor
{
template <typename X>
void DecodeIntegral( X& x, const IOBuffer::ConstSPtr& buffer, size_t& index )
{
if( std::is_same<X, uint8_t>::value )
{
x = buffer->At(index);
}
else if( std::is_same<X, int8_t>::value )
{
x = static_cast<int8_t>( buffer->At(index) );
}
else if( std::is_same<X, uint16_t>::value )
{
x = cl::ByteConversion::UbytesToUInt16( UByteArray<2>{{
buffer->At(index + 0),
buffer->At(index + 1) }}
);
}
else if( std::is_same<X, int16_t>::value )
{
x = cl::ByteConversion::UbytesToInt16( UByteArray<2>{{
buffer->At(index + 0),
buffer->At(index + 1) }}
);
}
else if( std::is_same<X, uint32_t>::value )
{
x = cl::ByteConversion::UbytesToUInt32( UByteArray<4>{{
buffer->At(index + 0),
buffer->At(index + 1),
buffer->At(index + 2),
buffer->At(index + 3) }}
);
}
else if( std::is_same<X, int32_t>::value )
{
x = cl::ByteConversion::UbytesToInt32( UByteArray<4>{{
buffer->At(index + 0),
buffer->At(index + 1),
buffer->At(index + 2),
buffer->At(index + 3) }}
);
}
else if( std::is_same<X, uint64_t>::value )
{
x = cl::ByteConversion::UbytesToUInt64( UByteArray<8>{{
buffer->At(index + 0),
buffer->At(index + 1),
buffer->At(index + 2),
buffer->At(index + 3),
buffer->At(index + 4),
buffer->At(index + 5),
buffer->At(index + 6),
buffer->At(index + 7) }}
);
}
else if( std::is_same<X, int64_t>::value )
{
x = cl::ByteConversion::UbytesToInt64( UByteArray<8>{{
buffer->At(index + 0),
buffer->At(index + 1),
buffer->At(index + 2),
buffer->At(index + 3),
buffer->At(index + 4),
buffer->At(index + 5),
buffer->At(index + 6),
buffer->At(index + 7) }}
);
}
// Increment the index in the buffer
index += sizeof(X);
}
template <typename X>
void operator()( X& x, const IOBuffer::ConstSPtr& buffer, size_t& index )
{
if( std::is_integral<X>::value )
{
DecodeIntegral( x, buffer, index );
}
}
};
代码在这里被调用:
DecoderFunctor func;
IterateOverTuple( func, data, buffer, index );
所以整型的一切都很好,它们被完美地解码了。然而,当我想尝试实现一个新的解码方法(数组),它没有编译:
std::tuple<std::array<uint16_t, 100>, std::array<uint8_t, 100>> data;
这是错误(gcc-4.9)。
所以我不明白为什么我得到这个错误。由于测试std::is_integral<X>::value
,数据不应该在DecodeIntegral( x, buffer, index );
中评估,对吗?
请不要说这是正在进行的工作,所以肯定有一些错误和改进。谢谢你的帮助!
我承认我没有看完所有的代码,但我相信你的问题是运行时与编译时条件。您不能使用运行时条件(如if (std::is_integral<:::>::value>)
)来防止编译时错误。
我理解DecodeIntegral
只有在X
确实是整型时才可编译。因此,您必须确保对DecodeIntegral
的非整型X
的调用永远不会被编译器看到(即实例化),而不仅仅是在运行时永远不会发生。
看到函数DecodeIntegral
可以很容易地成为一个静态成员而不改变语义,你可以使用"委托给类"的技巧来实现这一点。将DecodeIntegral
移动到helper类中:
template <bool Integral>
struct Helper;
template <>
struct Helper<true>
{
template <class X>
static void Decode( X& x, const IOBuffer::ConstSPtr& buffer, size_t& index )
{
// Old code of DecodeIntegral() goes here
}
};
template <>
struct Helper<false>
{
template <class X>
static void Decode( X& x, const IOBuffer::ConstSPtr& buffer, size_t& index )
{
// Code for non-integral decoding goes here
}
};
struct DecoderFunctor
{
template <typename X>
void operator()( X& x, const IOBuffer::ConstSPtr& buffer, size_t& index )
{
Helper<std::is_integral<X>::value>::Decode(x, buffer, index);
}
};
根据评论
中的请求添加如果需要多个标识符,请向帮助器添加更多bool
模板参数。如果你需要的鉴别器没有标准谓词,你可以自己写。
(下面的例子假设两个鉴别符是互斥的——最多只有一个为真):
// Two-discriminator helper
template <bool Integral, bool Array>
struct Helper;
template <>
struct Helper<true, false>
{
void Decode() { /* integral decode */ }
};
template <>
struct Helper<false, true>
{
void Decode() { /* array decode */ }
};
// Custom predicate
template <class T>
struct IsStdArray : std::false_type
{};
template <class T, size_t N>
struct IsStdArray<std::array<T, N>> : std::true_type
{};
// Usage
struct DecoderFunctor
{
template <typename X>
void operator()( X& x, const IOBuffer::ConstSPtr& buffer, size_t& index )
{
Helper<
std::is_integral<X>::value,
IsStdArray<X>::value
>::Decode(x, buffer, index);
}
};
std::is_integral<X>::value
求值为false
,但这并不意味着"跳过"下面的代码(DecodeIntegral( x, buffer, index );
)。编译器也会看到这一行。因此,当前您有一个运行时条件,但实际上您需要一个编译时条件。