I have a piece of code that I tried to automatically decode a buffer given the awaited data types. The data are represented as tuples:
std::tuple<uint8_t, int32_t> data;
size_t bufferIndex;
IOBuffer::ConstSPtr buffer( std::make_shared<IOBuffer>(5) );
I also have tuple heplers to iterate over the tuples and execute a functor for each one:
//-------------------------------------------------------------------------
//
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);
}
};
And here is my decoder functor:
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 );
}
}
};
And this is where the code is called:
DecoderFunctor func;
IterateOverTuple( func, data, buffer, index );
So everything works fine with integral types and they are decoded perfectly. However when I wanted to try to implement a new decoding method (for arrays), it didn't compile:
std::tuple<std::array<uint16_t, 100>, std::array<uint8_t, 100>> data;
Here is the error (gcc-4.9).
So I don't understand why I get this error. Because of the test std::is_integral<X>::value
the data should not be evaluated in DecodeIntegral( x, buffer, index );
right ?
Please not the this is work in progress so there are certainly a few mistakes and improvements to make. And thank you for your help !
I admit I haven't gone through all of the code, but I believe your issue is with runtime vs. compile-time conditions. You cannot use a run-time condition (like if (std::is_integral<:::>::value>)
to prevent compile-time errors.
I understand DecodeIntegral
is only compilable when X
is indeed integral. Therefore, you must make sure a call to DecodeIntegral
with a non-integral X
is never seen by the compiler (ie instantiated), and not just that it never occurs at runtime.
Seeing as the function DecodeIntegral
could easily be a static member without any change in semantics, you can use the "delegate to class" trick to achieve this. Move DecodeIntegral
into a helper class:
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);
}
};
Added based on request in comment
If you need more than one discriminator, add more bool
template parameters to the helper. If there is no standard predicate for a discriminator you need, you can write your own.
(The example below assumes the discriminators are exclusive - at most one is true):
// 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);
}
};
The std::is_integral<X>::value
evaluates to false
, but that does not mean that the code below ( DecodeIntegral( x, buffer, index );
) is "skipped". The compiler sees this line, too. So, currently you have a runtime-condition, but you actually want a compile-time condition.
Edit: I just wanted to edit my answer with a short example, but Angew was faster. See his answer :)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.