C++11 给了我们std::add_const
;使用 C++17,我们有一个新的结构 - std::as_const()
. 前者只是const
在你提供的类型之前加上一个。第二个是正确的(a 的模板)函数,而不是类型特征,它似乎做同样的事情 - 除了当类型是右值引用时,在这种情况下它不能使用。
我不太明白提供的动机std::as_const()
。为什么我们还需要它std::add_const
?
C++11 给了我们std::add_const
;使用 C++17,我们有一个新的结构 - std::as_const()
. 前者只是const
在你提供的类型之前加上一个。第二个是正确的(a 的模板)函数,而不是类型特征,它似乎做同样的事情 - 除了当类型是右值引用时,在这种情况下它不能使用。
我不太明白提供的动机std::as_const()
。为什么我们还需要它std::add_const
?
“需要”是一个强有力的词……std::as_const
存在是因为它有用,而不是绝对必要。由于它是一个函数而不是一个特征,我们可以使用它来“添加 const”到实际值而不是类型。
更具体地说:假设我有一些变量my_value
,我想把它当作一个const
,而不是复制它。在 C++17 之前,我需要编写:
static_cast<const MyType&>(my_value)
如果我不想明确指定类型,它将是:
static_cast<std::add_const_t<std::remove_reference_t<decltype(my_value)>> &>(my_value)
或者,如果您想低调而肮脏,并使用 C 风格的强制转换:
(const decltype(my_value) &) (&my_value)
所有这些都很烦人和冗长。
而不是这些,现在用 C++17 编写std::as_const(my_value)
,这就是它的全部。
笔记:
这个函数对右值引用是禁用的,即使它对它们工作得很好。原因是为了帮助您避免无意中保留对暂时过去其破坏的引用。正如@NicolBolas 解释的那样,如果您编写如下内容:
for(auto &x : std::as_const(returns_container())) { /* do stuff with x */ }
然后返回的容器的生命周期在循环的第一次迭代之前结束。很容易错过!
有关其他 (?) 信息,请参阅此实用函数的官方命题:P007R1,作者 Adam David Alan Martin 和 Alisdair Meredith。
您可能想要重载 const、no-const 并强制其中一个重载:
template<class T> [[nodiscard]]
T twice(T const& t){return t + t;}
template<class T>
void twice(T& t){t += t;}
您可以通过添加const
和使用非修改重载来保护输入。
double t = 5.;
twice(t); // t == 10
double const u = 5.;
double ux2 = twice(u); // ux2 == 10, u == 5.;
double v = 5.;
double vx2 = twice(std::as_const(v)); // vx2 == 10., v==5. It saves you from
// creating a const-reference
// `double const& ucr = u;` just to pass
// to the function.
我并不是说这是一个好的设计,只是为了说明这一点。找到更有用的案例只是时间问题。
一个更好的名字std::as_const
可能是std::protect
IMO。