C ++在类中保留更改的跟踪

时间:2017-01-17 09:35:44

标签: c++ oop optional members

想象一下代表邮件的类:

class mail {
    string subject;
    string content;
    date receivedDate;
};

现在我想要实现的是知道我的邮件数据是否已设置,一旦设置了哪些,哪些更改了。我可以使用std :: optional和std :: map的组合,如下所示:

class Mail {
    std::optional<string> subject;
    std::optional<string> content;
    std::optional<date>   receivedDate;

    enum EField { Subject, Content, ReceivedDate };

    typedef std::map<EField, bool> ChangedMap;

    ChangedMap changedFields;

public:
    Mail(optional<string> subject, ... ) {
        // initialize map with fields... hard coded
    }

    bool HasSubject() const { return subject; }

    string GetSubject() const { return subject.get(); }

    void SetSubject(const std::string& newSubject) {
        subject = newSubject;
        changedFields[Subject] = true;
    }

    void RemoveSubject() {
        changedFields[Subject] = HasSubject();
        subject.reset();
    }

    bool IsSubjectChanged() const {
        return changedFields[Subject];
    }
};

但我真的觉得我在这里缺少一些至关重要的东西。你会看到更好的方法吗,最好是内存使用量少,没有硬编码值?

我考虑过从std :: optional继承,但我也认为它不是一件好事。

由于

1 个答案:

答案 0 :(得分:1)

让我们概括一下这个问题:给定一个类型T,我想要一个包装器tracked<T>来跟踪运行时读/写的历史。

我会使用std::tuple和元编程来解决这个问题。首先,让我们用mail

来定义std::tuple
class mail
{
private:
    std::tuple<string, string, date> _data;

public:
    // `variant_type` could be automatically computed from the
    // tuple type.
    using variant_type = std::variant<string, string, date>; 

    enum class index
    {
        subject = 0,
        content = 1,
        date = 2
    };

    template <index TIndex>
    decltype(auto) access()
    {
        return std::get<static_cast<std::size_t>(TIndex)>(_data);
    } 
};

然后我会创建类似tracked<T>的内容来跟踪T上执行的操作:

template <typename T>
class tracked
{
private:
    using index_type = typename T::index;
    using variant_type = typename T::variant_type;

    struct write_action
    {
        variant_type _before;
        variant_type _after;
    };

    struct read_action
    {
         index_type _index;
    };

    T _data;
    std::vector<std::variant<write_action, read_action>> _history;

public:
    template <index TIndex>
    const auto& read() const 
    {
        _history.emplace_back(read_action{TIndex});
        return _data.access<TIndex>();
    }

    template <index TIndex, typename T>
    void write(T&& new_value) const 
    {
        // Remember previous value.
        variant_type _before{_data.access<TIndex>()};

        _history.emplace_back(write_action{_before, new_value});
        return _data.access<TIndex>() = std::forward<T>(new_value);
    }
};

上面的代码并不完全正确,因为您需要 action 类型的构造函数,异常处理,移动语义支持等等。我希望你能得到一般的想法。