从 CArchive 读取 WORD 变量并同时转换为 int

Posted

技术标签:

【中文标题】从 CArchive 读取 WORD 变量并同时转换为 int【英文标题】:Reading a WORD variable from a CArchive and casting to int at the same time 【发布时间】:2019-11-07 09:55:50 【问题描述】:

这听起来很简单,但是:

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

【问题讨论】:

【参考方案1】:

我认为没有直接的方法。你可以实现一个辅助函数:

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

在你的程序中使用fixed-width integer types 可能会更好,即也许int_least16_t 而不是int 以确保类型具有正确的大小。 WORD 是 fixed 到 16 位,但 int 不是。此外,WORD 未签名,int 未签名,因此在转换过程中可能会溢出。

【讨论】:

谢谢。我的数字很小,从 0 到 151。我也许可以调整为使用 int_least16_t。以前没有使用过这些类型。 好吧,那么uint_least8_t 比较合适。 我从来没有在自己的代码中真正使用过template(除了地图和列表)。但我明白这很有用,因为我们可以传递许多对组合并拥有一个功能。 :) 不错。【参考方案2】:

如果您希望序列化语法保持一致,这是一个如何创建包装器的示例。它被设计为仅适用于整数和 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 保存为 int 将 2 保存为 BYTE 将 3 保存为 WORD 将 4 保存为 DWORD

加载为 int 加载为 BYTE 加载为 WORD 加载为 DWORD

【讨论】:

很棒的高级东西!从来没有意识到还有 std::is_same_v。

以上是关于从 CArchive 读取 WORD 变量并同时转换为 int的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中读取 CArchive 布尔值

CFile与CArchive区别

从 CArchive 文件中检索信息

CArchive (MFC) 到 JSON?

文件序列化

从 UILocalNotification 打开应用程序时转到视图控制器