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

ein*_*ica 19 c++ const rationale type-traits c++17

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

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

ein*_*ica 20

"需要"是一个强有力的词...... std::as_const存在是因为它有用,而不是绝对必要.因为它是一个函数而不是一个特征,我们可以用它来"添加const"到实际而不是类型.

更具体地说:假设我有一些变量my_value,我想把它当作a const,但不要复制它.在C++ 17之前,我需要写:

static_cast<const MyType&>(my_value)
Run Code Online (Sandbox Code Playgroud)

如果我不想明确指定类型,它将是:

static_cast<std::add_const_t<std::remove_reference_t<decltype(my_value)>> &>(my_value)
Run Code Online (Sandbox Code Playgroud)

或者如果你想变得肮脏,并使用C风格的铸造:

(const decltype(my_value) &) (my_value)
Run Code Online (Sandbox Code Playgroud)

所有这些都令人烦恼和冗长.

而不是这些,用C++ 17现在写std::as_const(my_value),这就是它的全部.

笔记:

  • 对于右值引用,此函数被禁用,即使它对它们工作正常.原因是为了帮助你避免无意中提到一个临时的破坏.正如@NicolBolas解释的那样,如果你写的东西如下:

    for(auto &x : std::as_const(returns_container())) { /* do stuff with x */ }
    
    Run Code Online (Sandbox Code Playgroud)

    然后返回的容器的生命周期在循环的第一次迭代之前结束.很容易错过!

  • 有关其他(?)信息,请参阅此实用功能的官方提议:P007R1,Adam David Alan Martin和Alisdair Meredith.

  • @einpoklum:它将生命结束到完整的表达.但是如果你正在做`for(auto&val:std :: as_const(returns_container()))`,那么"完整表达式"会在`for`循环开始之前结束.如果您直接使用`returns_container()`,临时的生命周期将扩展到整个`for`循环.更好地防止人们在前面犯这个错误. (2认同)

alf*_*lfC 9

您可能想要重载 const、no-const 并强制重载之一:

template<class T> [[nodiscard]]
T twice(T const& t){return t + t;}

template<class T>
void twice(T& t){t += t;}
Run Code Online (Sandbox Code Playgroud)

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.
Run Code Online (Sandbox Code Playgroud)

我并不是说这是一个好的设计,只是为了说明这一点。找到更有用的案例只是时间问题。


std::as_constIMO可能是一个更好的名字std::protect

  • “更好的名称是‘std::protect’”+1。这比大多数实际解释更好地解释了它。 (4认同)