Чтение переменной WORD из CArchive и приведение к int одновременно - PullRequest
3 голосов
/ 07 ноября 2019

Это может звучать просто, но:

WORD wSong = 0;
CArchive ar;
...
ar >> wSong;
m_sPublicTalkInfo.iSongStart = static_cast<int>(wSong);

В данный момент я читаю WORD в определенную переменную и применяю ее.

Могу ли я прочитать ее и привести кв то же время?

Обратите внимание, я не могу сериализовать int. Это должно быть WORD и приведение к int. Или

ar >> wSong;
m_sPublicTalkInfo.iSongStart = static_cast<int>(wSong);

Ответы [ 2 ]

5 голосов
/ 07 ноября 2019

Я не думаю, что есть прямой путь. Вы могли бы реализовать вспомогательную функцию:

template <typename T, typename U>
T readAndCast (CArchive& ar) {
  U x;
  ar >> x;
  return static_cast<T> (x);
}


m_sPublicTalkInfo.iSongStart = readAndCast<int, WORD>(ar);

Возможно, было бы лучше использовать целочисленные типы фиксированной ширины в вашей программе, то есть, возможно, int_least16_t вместо int, чтобы бытьуверен, что тип имеет правильный размер. WORD является фиксированным до 16 бит, но int нет. Кроме того, WORD не подписано, а int нет, поэтому во время приведения может произойти переполнение.

2 голосов
/ 08 ноября 2019

Это пример того, как вы можете создать оболочку, если хотите, чтобы синтаксис сериализации оставался непротиворечивым. Он предназначен для работы только с целыми числами и беззнаковыми типами MFC.

#include <iostream>
#include <cstdint>
#include <sstream>
#include <type_traits>

// Fake the MFC types
using BYTE = std::uint8_t;
using WORD = std::uint16_t;
using DWORD = std::uint32_t;
using QWORD = std::uint64_t;

template<typename T>
struct is_valid_save_type : std::bool_constant<
    std::is_same_v<BYTE, T> ||
    std::is_same_v<WORD, T> ||
    std::is_same_v<DWORD, T> ||
    std::is_same_v<QWORD, T>
> {};

template<typename T>
struct is_valid_load_type : is_valid_save_type<T> {};

// Saves type T as a SaveType
template<typename T, typename SaveType>
struct save_as_type
{
    explicit save_as_type(T value) : value(value) {}

    explicit operator SaveType() const
    {
        return static_cast<SaveType>(value);
    }

private:
    T value;

    // This class only works with integrals
    static_assert(std::is_integral_v<T>);

    // SaveType should be BYTE/WORD/DWORD/QWORD only
    static_assert(is_valid_save_type<SaveType>::value);
};

// Loads type T as a LoadType
template<typename T, typename LoadType>
struct load_as_type
{
    explicit load_as_type(T& value) : value_(value) {}

    load_as_type& operator=(LoadType rhs)
    {
        value_ = rhs;
        return *this;
    }

private:
    T& value_;

    // T should be an integral
    static_assert(std::is_integral_v<T>);

    // T must be non-constant
    static_assert(!std::is_const_v<T>);

    // LoadType should be BYTE/WORD/DWORD/QWORD only
    static_assert(is_valid_load_type<LoadType>::value);
};

class CArchive;

// Make the above types serializable
template<typename T, typename SaveType>
CArchive& operator<<(CArchive& ar, save_as_type<T, SaveType> const& s)
{
    ar << static_cast<SaveType>(s);
}

template<typename T, typename LoadType>
CArchive& operator>>(CArchive& ar, load_as_type<T, LoadType> l)
{
    LoadType t{};
    ar >> t;
    l = t;
}

// Use the following two functions in your code
template<typename SaveType, typename T>
save_as_type<T, SaveType> save_as(T const& t)
{
    return save_as_type<T, SaveType>{ t };
}

template<typename LoadType, typename T>
load_as_type<T, LoadType> load_as(T& t)
{
    return load_as_type<T, LoadType>{ t };
}

// Prevent loading into temporaries; i.e. load_as<BYTE>(11);
template<typename T, typename LoadType>
load_as_type<T, LoadType> load_as(const T&& t) = delete;

// Fake MFC Archive
class CArchive
{
public:
    CArchive& operator<<(int i)
    {
        std::cout << "Saving " << i << " as an int\n";
        return *this;
    }

    CArchive& operator<<(BYTE b)
    {
        std::cout << "Saving " << (int)b << " as a BYTE\n";
        return *this;
    }

    CArchive& operator<<(WORD w)
    {
        std::cout << "Saving " << (int)w << " as a WORD\n";
        return *this;
    }

    CArchive& operator<<(DWORD d)
    {
        std::cout << "Saving " << (int)d << " as a DWORD\n";
        return *this;
    }

    CArchive& operator>>(int& i)
    {
        std::cout << "Loading as an int\n";
        return *this;
    }

    CArchive& operator>>(BYTE& b)
    {
        std::cout << "Loading as a BYTE\n";
        return *this;
    }

    CArchive& operator>>(WORD& w)
    {
        std::cout << "Loading as a WORD\n";
        return *this;
    }

    CArchive& operator>>(DWORD& d)
    {
        std::cout << "Loading as a DWORD\n";
        return *this;
    }
};

int main()
{
    CArchive ar;

    int out_1 = 1;
    int out_2 = 2;
    int out_3 = 3;
    int out_4 = 4;

    ar << out_1 <<
        save_as<BYTE>(out_2) <<
        save_as<WORD>(out_3) <<
        save_as<DWORD>(out_4);

    std::cout << "\n";

    int in_1 = 0;
    int in_2 = 0;
    int in_3 = 0;
    int in_4 = 0;

    ar >> in_1 >>
        load_as<BYTE>(in_2) >>
        load_as<WORD>(in_3) >>
        load_as<DWORD>(in_4);

    return 0;
}

Вывод:

Сохранение 1 в виде целого числа
Сохранение 2 в виде байта
Сохранение 3 в виде слова
Сохранение 4 в виде DWORD

Загрузка в виде целого числа
Загрузка в виде байта
Загрузка в виде слова
Загрузка в виде значения DWORD

...