Herb Sutter 的 回归基础! CppCon 上的现代 C++ 基础介绍 讨论了传递参数的不同选项,并比较了它们的性能与编写/教学的难易程度。 “高级”选项(在所有测试的情况下提供最佳性能,但对于大多数开发人员来说太难编写)是完美的转发,给出的示例 (PDF, pg. 28) :
class employee {
std::string name_;
public:
template <class String,
class = std::enable_if_t<!std::is_same<std::decay_t<String>,
std::string>::value>>
void set_name(String &&name) noexcept(
std::is_nothrow_assignable<std::string &, String>::value) {
name_ = std::forward<String>(name);
}
};
示例使用带有转发引用的模板函数,模板参数为String
使用 enable_if
进行约束.然而,约束似乎是不正确的:似乎是说这种方法只能在 String
的情况下使用。类型不是 std::string
,这是没有意义的。这意味着这个 std::string
可以使用 任何东西设置成员,但 std::string
值(value)。
using namespace std::string_literals;
employee e;
e.set_name("Bob"s); // error
我考虑过的一个解释是,有一个简单的错字,而约束是 std::is_same<std::decay_t<String>, std::string>::value
而不是 !std::is_same<std::decay_t<String>, std::string>::value
.但是,这意味着 setter 不能使用,例如 const char *
鉴于这是演示文稿中测试的案例之一,显然它旨在与这种类型一起使用。
在我看来,正确的约束更像是:
template <class String,
class = std::enable_if_t<std::is_assignable<decltype((name_)),
String>::value>>
void set_name(String &&name) noexcept(
std::is_nothrow_assignable<decltype((name_)), String>::value) {
name_ = std::forward<String>(name);
}
允许任何可以分配给成员的东西与 setter 一起使用。
我有正确的约束吗?还有其他可以改进的地方吗?对原始约束是否有任何解释,也许是断章取义?
我还想知道这个声明中复杂的、“不可教”的部分是否真的那么有益。由于我们没有使用重载,我们可以简单地依赖正常的模板实例化:
template <class String>
void set_name(String &&name) noexcept(
std::is_nothrow_assignable<decltype((name_)), String>::value) {
name_ = std::forward<String>(name);
}
当然,关于 noexcept
真的很重要,有人说除了移动/交换原语外不要太担心:
template <class String>
void set_name(String &&name) {
name_ = std::forward<String>(name);
}
也许对于概念来说,约束模板不会非常困难,只是为了改进错误消息。
template <class String>
requires std::is_assignable<decltype((name_)), String>::value
void set_name(String &&name) {
name_ = std::forward<String>(name);
}
这仍然有缺点,它不能是虚拟的,而且它必须在标题中(尽管希望模块最终会呈现这种情况),但这似乎相当可教。
最佳答案
我认为你所拥有的可能是正确的,但为了不写一个简单的“我同意”的“答案”,我会提出这个建议,而不是根据正确的类型检查分配 - 是否是 lval , rval, const, 随便什么:
template <class String>
auto set_name(String&& name)
-> decltype(name_ = std::forward<String>(name), void()) {
name_ = std::forward<String>(name);
}
关于c++ - 完美转发 setter 的正确 `enable_if` 约束是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26147491/