2

我希望能够使用移动语义或复制语义来初始化类的每个字段。构造函数都将使用基本相同的代码进行构造,如下所示:

LogRecord::LogRecord(const Logger &logger, LogLevel level, const std::wstring &message)
    : level(level), logger_name(logger.GetName()), message(message), sequence_number(LogRecord::record_count++), source_class_name(), source_method_name(), time(std::chrono::system_clock::now()) {
}
LogRecord::LogRecord(const Logger &logger, LogLevel level, std::wstring &&message)
    : level(level), logger_name(logger.GetName()), message(message), sequence_number(LogRecord::record_count++), source_class_name(), source_method_name(), time(std::chrono::system_clock::now()) {
}
LogRecord::LogRecord(const Logger &logger, LogLevel level, const std::wstring &message, const std::wstring &source_class_name, const std::wstring &source_method_name)
    : level(level), logger_name(logger.GetName()), message(message), sequence_number(LogRecord::record_count++), source_class_name(source_class_name), source_method_name(source_method_name), time(std::chrono::system_clock::now()) {
}
LogRecord::LogRecord(const Logger &logger, LogLevel level, std::wstring &&message, const std::wstring &source_class_name, const std::wstring &source_method_name)
    : level(level), logger_name(logger.GetName()), message(message), sequence_number(LogRecord::record_count++), source_class_name(source_class_name), source_method_name(source_method_name), time(std::chrono::system_clock::now()) {
}
LogRecord::LogRecord(const Logger &logger, LogLevel level, const std::wstring &message, std::wstring &&source_class_name, const std::wstring &source_method_name)
    : level(level), logger_name(logger.GetName()), message(message), sequence_number(LogRecord::record_count++), source_class_name(source_class_name), source_method_name(source_method_name), time(std::chrono::system_clock::now()) {
}
LogRecord::LogRecord(const Logger &logger, LogLevel level, std::wstring &&message, std::wstring &&source_class_name, const std::wstring &source_method_name)
    : level(level), logger_name(logger.GetName()), message(message), sequence_number(LogRecord::record_count++), source_class_name(source_class_name), source_method_name(source_method_name), time(std::chrono::system_clock::now()) {
}

等等

有没有比简单地为每个可能的组合声明一个构造函数更好的方法来解决这个问题,就像这样?

class LogRecord {
public:
    LogRecord(const Logger &logger, LogLevel level, const std::wstring &message);
    LogRecord(const Logger &logger, LogLevel level, std::wstring &&message);
    LogRecord(const Logger &logger, LogLevel level, const std::wstring &message, const std::wstring &source_class_name, const std::wstring &source_method_name);
    LogRecord(const Logger &logger, LogLevel level, std::wstring &&message, const std::wstring &source_class_name, const std::wstring &source_method_name);
    LogRecord(const Logger &logger, LogLevel level, const std::wstring &message, std::wstring &&source_class_name, const std::wstring &source_method_name);
    LogRecord(const Logger &logger, LogLevel level, std::wstring &&message, std::wstring &&source_class_name, const std::wstring &source_method_name);
    LogRecord(const Logger &logger, LogLevel level, const std::wstring &message, const std::wstring &source_class_name, std::wstring &&source_method_name);
    LogRecord(const Logger &logger, LogLevel level, std::wstring &&message, const std::wstring &source_class_name, std::wstring &&source_method_name);
    LogRecord(const Logger &logger, LogLevel level, const std::wstring &message, std::wstring &&source_class_name, std::wstring &&source_method_name);
    LogRecord(const Logger &logger, LogLevel level, std::wstring &&message, std::wstring &&source_class_name, std::wstring &&source_method_name);
    ...
private:
    std::wstring message, source_class_name, source_method_name;
    ...
};

这是一个简化的表格,使其更易于阅读。 Object是具有成员的类,并且Member是成员的类型名。该Member类型定义了一个复制构造函数和一个移动构造函数。

基本上,我的问题是如何以更少的代码重复执行以下操作:

class Object {
public:
    Object(const Member &x, const Member &y, const Member &z) : x(x), y(y), z(z) {}
    Object(Member &&x, const Member &y, const Member &z) : x(x), y(y), z(z) {}
    Object(const Member &x, Member &&y, const Member &z) : x(x), y(y), z(z) {}
    Object(Member &&x, Member &&y, const Member &z) : x(x), y(y), z(z) {}
    Object(const Member &x, const Member &y, Member &&z) : x(x), y(y), z(z) {}
    Object(Member &&x, const Member &y, Member &&z) : x(x), y(y), z(z) {}
    Object(const Member &x, Member &&y, Member &&z) : x(x), y(y), z(z) {}
    Object(Member &&x, Member &&y, Member &&z) : x(x), y(y), z(z) {}
private:
    Member x, y, z;
}
4

1 回答 1

2

我不会为所有这些超载而烦恼。始终std::wstring按值获取参数,并将std::move它们放在 mem-initializer 中。那么你只需要 3 个构造函数定义。需要注意的是,在传递右值的情况下,您会产生额外的移动构造,但您很可能会忍受这种情况。

LogRecord(const Logger &logger, LogLevel level, std::wstring message)
    : level(level), logger_name(logger.GetName()), message(std::move(message)), ...
    {}

请注意,由于小字符串优化,对于较小的n值,移动构造实际上可能是O(n) 。


如评论中所述,另一种选择是完美转发。你可以做类似的事情

template<typename Message>
LogRecord(const Logger &logger, LogLevel level, Message&& message)
    : level(level), logger_name(logger.GetName()), message(std::forward<Message>(message)), ...
    {}

也许添加static_asserts 以打印更好的错误消息Message,或者可以转换为std::wstring.

于 2015-04-16T14:19:13.510 回答