简体   繁体   English

std :: array编译时间扣除

[英]std::array compile time deduction

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: 我也有元组heplers迭代元组并为每个元素执行一个仿函数:

//-------------------------------------------------------------------------
//
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). 是错误(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 ); 由于测试std::is_integral<X>::value ,不应在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. 您不能使用运行时条件(如if (std::is_integral<:::>::value>)来防止编译时错误。

I understand DecodeIntegral is only compilable when X is indeed integral. 我知道当X确实是积分时, DecodeIntegral只能编译。 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. 因此,您必须确保编译器永远不会看到带有非整数X DecodeIntegral调用(即实例化),而不仅仅是它永远不会在运行时发生。

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. 看作函数DecodeIntegral可以很容易地成为一个静态成员而没有任何语义变化,你可以使用“delegate to class”技巧来实现这一点。 Move DecodeIntegral into a helper class: DecodeIntegral移动到辅助类中:

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. 如果需要多个鉴别器,请向辅助对象添加更多bool模板参数。 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". std::is_integral<X>::value计算结果为false ,但这并不意味着下面的代码( DecodeIntegral( x, buffer, index ); )被“跳过”。 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. 编辑:我只是想用一个简短的例子来编辑我的答案,但是Angew更快。 See his answer :) 看他的回答:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM