32

C++11 给了我们std::add_const;使用 C++17,我们有一个新的结构 - std::as_const(). 前者只是const在你提供的类型之前加上一个。第二个是正确的(a 的模板)函数,而不是类型特征,它似乎做同样的事情 - 除了当类型是右值引用时,在这种情况下它不能使用。

我不太明白提供的动机std::as_const()。为什么我们还需要它std::add_const

4

2 回答 2

37

“需要”是一个强有力的词……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。

于 2018-11-23T16:46:48.333 回答
8

您可能想要重载 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::protectIMO。

于 2020-09-01T07:36:41.463 回答