std :: вычеты времени компиляции массива

#c #compile-time #stdtuple

#c #время компиляции #stdtuple

Вопрос:

У меня есть фрагмент кода, который я пытался автоматически декодировать в буфере с учетом ожидаемых типов данных. Данные представлены в виде кортежей:

 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( Functionamp; f, std::tuple<Tuples...>amp; t,
                       Argsamp;... 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()( Functionamp; f, Tupleamp; t, Argsamp;... 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()( Functionamp; f, Tupleamp; t, Argsamp;... )
    {
        cl::Ignore(f);
        cl::Ignore(t);
    }
};
  

И вот мой функтор декодера:

 struct DecoderFunctor
{
    template <typename X>
    void DecodeIntegral( Xamp; x, const IOBuffer::ConstSPtramp; buffer, size_tamp; 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()( Xamp; x, const IOBuffer::ConstSPtramp; buffer, size_tamp; 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 ); правильно?

Пожалуйста, не указывайте, что это незавершенная работа, поэтому, безусловно, есть несколько ошибок и улучшений. И спасибо вам за вашу помощь!

Ответ №1:

Я признаю, что я не прошел весь код, но я считаю, что ваша проблема связана с условиями выполнения и времени компиляции. Вы не можете использовать условие времени выполнения (например 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( Xamp; x, const IOBuffer::ConstSPtramp; buffer, size_tamp; index )
  {
    // Old code of DecodeIntegral() goes here
  }  
};

template <>
struct Helper<false>
{
  template <class X>
  static void Decode( Xamp; x, const IOBuffer::ConstSPtramp; buffer, size_tamp; index )
  {
    // Code for non-integral decoding goes here
  }
};

struct DecoderFunctor
{
    template <typename X>
    void operator()( Xamp; x, const IOBuffer::ConstSPtramp; buffer, size_tamp; 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()( Xamp; x, const IOBuffer::ConstSPtramp; buffer, size_tamp; index )
    {
        Helper<
            std::is_integral<X>::value,
            IsStdArray<X>::value
        >::Decode(x, buffer, index);
    }
};
  

Комментарии:

1. Вы правы, в этих случаях я должен научиться больше думать о времени компиляции, а не о времени выполнения. Кстати, есть ли способ определить во время компиляции, что данные являются std::array ? (std::is_array в моем случае не работает)

2. @Athanase я расширил ответ

3. Методы шаблонов действительно невероятны. Это чудесно :).

Ответ №2:

std::is_integral<X>::value Вычисляется false , но это не означает, что приведенный ниже код ( DecodeIntegral( x, buffer, index ); ) «пропущен». Компилятор тоже видит эту строку. Итак, в настоящее время у вас есть условие времени выполнения, но на самом деле вам нужно условие времени компиляции.

Редактировать: я просто хотел отредактировать свой ответ с помощью короткого примера, но Angew был быстрее. Смотрите его ответ 🙂

Комментарии:

1. Спасибо за ваш ответ!