Замена функтора на шаблонную функцию - PullRequest
0 голосов
/ 02 июня 2018

В настоящее время я работаю над обновлением моего старого проекта на C ++, стараясь использовать все преимущества современного C ++.Некоторая часть проекта была посвящена доступу к массиву uint8_t, возвращению uint8_t, uint16_t или uint32_t, в зависимости от необходимых данных.Для простоты вопроса я оставлю в стороне любые проблемы, связанные с порядком байтов.

Я сделал следующий класс, используя функтор для доступа к данным:

template<std::size_t sz>
class Read
{
public:
    template <std::size_t sz>
    struct Read_traits { };

    template <>
    struct Read_traits<8> { using internal_type = std::uint8_t; };

    template <>
    struct Read_traits<16> { using internal_type = std::uint16_t; };

    template <>
    struct Read_traits<32> { using internal_type = std::uint32_t; };

    template <>
    struct Read_traits<64> { using internal_type = std::uint64_t; };

    using read_type = typename Read_traits<sz>::internal_type;

    template<typename T, ::std::size_t N>
    read_type operator()(const ::std::array<T, N> & arr, const ::std::uint32_t& adr) const {
        read_type returnValue{};
        for (uint8_t i = 0; i <= sizeof(read_type) - 1; ++i) {
            returnValue <<= 8;
            returnValue |= arr[adr + i];
        }
        return returnValue;
    };
};

Использование

int main()
{
    std::array <uint8_t, 0x4> memory {0xFE, 0xDC, 0xBA, 0x98};
    Read<32> r32;
    auto val32 = r32(memory, 0);
    std::cout << "32 bits: 0x" << std::hex << val32 << std::endl;

    return 0;
}    

Это работает так, как я хочу, но мне было интересно, можно ли создать обычную функцию вместо функтора, все еще используя черты?

IE заменяет2-х строчный вызов функтора:

Read<32> r;
auto val = r(memory, 0);

с помощью одной строки:

auto val Read<32>(memory, 0);

Я пробовал несколько вещей, которые не были окончательными, и, поскольку я далек отБудучи экспертом в шаблонах, я могу гоняться за тем, что даже не выполнимо ...

Спасибо, что читаете меня:)

Ответы [ 2 ]

0 голосов
/ 02 июня 2018

Единственная причина для Read как класса, кажется, определение Read_traits.Но вы можете определить и последнее за пределами первого.Всего несколько дополнительных ключевых слов typename, необходимых из-за уродства C ++ ...

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

#include <cstdint>
#include <iostream>
#include <array>

template <std::size_t sz>
struct ReadType { };

template <>
struct ReadType <8> { using type = std::uint8_t; };

template <>
struct ReadType <16> { using type = std::uint16_t; };

template <>
struct ReadType <32> { using type = std::uint32_t; };

template <>
struct ReadType <64> { using type = std::uint64_t; };

template <std::size_t sz, typename T, ::std::size_t N>
typename ReadType<sz>::type read(const ::std::array<T, N> & arr, const ::std::uint32_t& adr) {
    using read_type = typename ReadType<sz>::type;
    read_type returnValue{};
    for (uint8_t i = 0; i <= sizeof(read_type) - 1; ++i) {
        returnValue <<= 8;
        returnValue |= arr[adr + i];
    }
    return returnValue;
};

int main()
{
    std::array <uint8_t, 0x4> memory {0xFE, 0xDC, 0xBA, 0x98};
    auto val32 = read<32>(memory, 0);
    std::cout << "32 bits: 0x" << std::hex << val32 << std::endl;

    return 0;
}
0 голосов
/ 02 июня 2018

Вы можете сделать это:

// Maps 8, 16 and 32 to uint8_t, uint16_t and uint32_t, respectively
template<size_t Size>
using SizedUInt = std::conditional_t<Size == 8, uint8_t,
                   std::conditional_t<Size == 16, uint16_t,
                    std::conditional_t<Size == 32, uint32_t, void>>>;

template<size_t Size, typename T, size_t N>
SizedUInt<Size> read(const std::array<T, N>& arr, uint32_t adr)
{
    SizedUInt<Size> returnValue{};
    for (uint8_t i = 0; i <= sizeof(SizedUInt<Size>) - 1; ++i) {
        returnValue <<= 8;
        returnValue |= arr[adr + i];
    }
    return returnValue;
}

SizedUInt - псевдоним шаблона, который выбирает правильный тип, используя вложенный шаблон conditional_t.Я установил тип false для самого глубокого conditional_t на void, чтобы вызвать ошибку компиляции, когда шаблон используется со значением, отличным от 8, 16 или 32.


Или вы можете сделать это, используя свой шаблонный класс:

// create a temporary of type Read<32> and call its call operator
auto val = Read<32>{}(memory, 0);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...