【问题标题】:std::array compile time deductionstd::array 编译时间扣除
【发布时间】:2014-06-26 08:59:10
【问题描述】:

我有一段代码尝试根据等待的数据类型自动解码缓冲区。数据表示为元组:

std::tuple<uint8_t, int32_t> data;
size_t bufferIndex;
IOBuffer::ConstSPtr buffer( std::make_shared<IOBuffer>(5) );

我也有元组 hepler 来迭代元组并为每个元组执行一个仿函数:

//-------------------------------------------------------------------------
//
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;

Here 是错误 (gcc-4.9)。

所以我不明白为什么会出现此错误。由于测试std::is_integral&lt;X&gt;::value,数据不应该在DecodeIntegral( x, buffer, index ); 中进行评估,对吗?

请注意,这是正在进行的工作,因此肯定存在一些错误和改进。并感谢您的帮助!

【问题讨论】:

    标签: c++ compile-time stdtuple


    【解决方案1】:

    我承认我没有浏览所有代码,但我相信您的问题在于运行时与编译时条件。您不能使用运行时条件(如 if (std::is_integral&lt;:::&gt;::value&gt;) 来防止编译时错误。

    我知道 DecodeIntegral 只有在 X 确实是不可分割的时候才可以编译。因此,您必须确保编译器永远不会看到带有非整数XDecodeIntegral(即实例化)(即实例化),而不仅仅是它永远不会在运行时发生。 p>

    看到函数DecodeIntegral 可以很容易地成为静态成员而无需更改语义,您可以使用“委托到类”技巧来实现这一点。将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);
        }
    };
    

    根据评论中的要求添加

    如果您需要多个鉴别器,请在帮助程序中添加更多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::array ? (std::is_array 在我的情况下不起作用)
    • @Athanase 我已经扩展了答案
    • 模板技术确实令人难以置信。这太棒了:)。
    【解决方案2】:

    std::is_integral&lt;X&gt;::value 的计算结果为 false,但这并不意味着下面的代码 (DecodeIntegral( x, buffer, index );) 被“跳过”。编译器也会看到这一行。所以,目前你有一个运行时条件,但你实际上想要一个编译时条件。

    编辑:我只是想用一个简短的例子来编辑我的答案,但 Angew 更快。看看他的回答:)

    【讨论】:

    • 感谢您的回答!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-16
    相关资源
    最近更新 更多