香草萨特的回到基础! CppCon的现代C++演示文稿讨论了传递参数的不同选项,并比较了它们的性能与易于编写/教学。 “高级”选项(在所有情况下提供最佳的性能测试,但太难对于大多数开发者编写)是完美转发,给定(PDF, pg. 28)的例子:完美转发设置器上的'enable_if`约束是什么?
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);
}
};
的示例使用转发的模板函数参考,其中使用enable_if
约束了模板参数String
。但是这个约束似乎是不正确的:似乎是说这种方法只有在String
类型不是std::string
时才可以使用,这是没有意义的。这意味着std::string
成员可以使用设置,除和std::string
之外的任何值。
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
。然而,这意味着制定者不适用于(例如)const char *
,并且显然它打算使用这种类型,因为这是在演示文稿中测试的案例之一。
在我看来,正确的约束更像是:
允许任何可以被分配给成员与二传手使用。
我得到了正确的约束吗?还有其他可以改进的地方吗?对原始约束是否有任何解释,或许它是脱离了语境?
另外我想知道这个声明中复杂的,“不可测试”的部分是否真的有益。因为我们没有使用过载,我们可以简单地依靠正常的模板实例:
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);
}
这仍然会对它不能是虚拟的缺点,它必须在头(虽然希望模块将最终渲染没有实际意义),但这似乎相当受教。
嗯,房间里有人说它的约束不正确,不接受字符串文字 - 也许我们可以cc @HowardHinnant?它也不适合我。 [视频的谈话](http://youtu.be/xnqTKD8uD64?t=1h15m21s) – dyp 2014-10-01 19:26:59
@PiotrS .: MSVC没有别名,所以我忘了:/ – 2014-10-01 21:10:34
@MooingDuck嘿,VS2013支持别名和他们的stdlib工具C++ 14 type_trait别名。 – bames53 2014-10-01 21:17:21