有没有一种非重复的方法允许程序员在成员初始化的复制和移动语义之间进行选择
Is there a non-repetitive way to allow the programmer to choose between copy and move semantics for member initialization?
我希望能够使用移动语义或复制语义初始化类的每个字段。构造函数都将使用基本相同的代码进行构造,如下所示:
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;
}
我不会为所有这些重载而烦恼。始终按值获取std::wstring
参数,并在 mem 初始值设定项中std::move
它们。然后你只需要 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_assert
s 以打印更好的错误消息,Message
是或可转换为std::wstring
。
相关文章:
- 不能将复制初始化与隐式转换的多个步骤一起使用
- 在引用初始化中使用已删除的复制构造函数进行复制初始化
- 为什么 std::string s = "123" 当不涉及副本时被视为复制初始化?
- 复制初始化:为什么即使关闭了复制省略,也没有调用move或copy构造函数
- 复制初始化与直接初始化已更改
- 为什么在直接初始化和赋值中传递 lambda 而不是在复制初始化中传递 lambda 时会编译?
- 复制初始化 - 从 'int' 类型转换为非标量类型
- 我可以制作一个对象方法,如果单独调用,它将自行修改,但如果在复制初始化期间调用,则会返回一个新对象?
- 如果值来自成员变量,则复制初始化和参考初始化之间的C 差异
- 复制初始化表单 '= {}'
- 对C++所做的更改使复制初始化适用于具有显式构造函数的类
- 显式强制转换、直接初始化和复制初始化之间的行为不同
- 是直接初始化还是复制初始化
- 为什么复制初始化是这样的?为什么需要复制构造函数
- 在复制初始化中,对复制构造函数的调用是显式的还是隐式的
- 复制列表初始化和传统复制初始化之间的任何区别
- 复制初始化和显式构造函数-编译器的差异
- 如何为显式重载构造函数启用复制初始化
- POD变量的直接初始化不起作用,但当将变量推到向量上时,复制初始化起作用
- 为什么类构造函数在通过复制初始化对象时不起作用