3

待っているデータ型を指定して、バッファを自動的にデコードしようとしたコードがあります。データはタプルとして表されます。

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

これは進行中の作業であるため、いくつかの間違いや改善点があることは間違いありません。そして、あなたの助けに感謝します!

4

2 に答える 2

5

すべてのコードを調べたわけではないことは認めますが、問題は実行時とコンパイル時の条件にあると思います。実行時の条件を使用することはできません (if (std::is_integral<:::>::value>)コンパイル時のエラーを防ぐなど)。

が実際に不可欠DecodeIntegralな場合にのみコンパイル可能であることを理解しています。Xしたがって、DecodeIntegral非整数を使用したXへの呼び出しが、実行時に発生しないだけでなく、コンパイラによって認識されないようにする (つまり、インスタンス化されない) ようにする必要があります。

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テンプレート パラメーターをヘルパーに追加します。必要な弁別子の標準述語がない場合は、独自の述語を記述できます。

(以下の例では、ディスクリミネーターが排他的であることを前提としています - 多くても 1 つが 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);
    }
};
于 2014-06-26T09:10:56.710 に答える
1

std::is_integral<X>::valueに評価されますが、これは ( ) の下のコードが「スキップ」さfalseれることを意味するものではありません。DecodeIntegral( x, buffer, index );コンパイラもこの行を認識します。したがって、現在、実行時条件がありますが、実際にはコンパイル時条件が必要です。

編集:短い例で回答を編集したかっただけですが、Angewの方が速かったです。彼の答えを見てください:)

于 2014-06-26T09:14:56.597 に答える