我们需要 std::as_const() 做什么?

What do we need std::as_const() for?

C++11 给了我们std::add_const; with C++17, we have a new structure - std::as_const()。前者只是在您提供的类型之前添加一个 const 。第二个是一个适当的(a 的模板)函数,而不是类型特征,它似乎做同样的事情 - 除非类型是右值引用,在这种情况下它不能使用。

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

“需要”是一个很重的词...std::as_const 存在是因为它有用,而不是绝对必要。由于它是一个函数而不是一个特征,我们可以用它来“添加常量”到实际的 values 而不是 types.

更具体地说:假设我有一些变量 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 和使用 non-modifying 重载来保护输入。

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。