【问题标题】:What do we need std::as_const() for?我们需要 std::as_const() 做什么?
【发布时间】:2019-04-26 06:47:54
【问题描述】:

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

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

【问题讨论】:

    标签: c++ constants c++17 typetraits rationale


    【解决方案1】:

    “需要”是一个强词...std::as_const 的存在是因为它有用,而不是绝对必要。由于它是一个函数而不是一个 trait,我们可以使用它来“添加 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。

    【讨论】:

    • "我不完全清楚为什么删除右值引用是必要的。" 因为如果您尝试使用 @,C++ 的临时生命周期扩展规则将无法正常工作987654330@他们。如果您曾经在临时上调用 as_const,您获得对已销毁对象的引用。
    • @NicolBolas:谢谢。但是 - 在使用 as_const() 的语句完全执行之前,临时不会生效吗?如果没有,你能链接到解释吗?
    • @einpoklum:它将持续到完整表达的尽头。但是,如果您正在执行类似for(auto &amp;val : std::as_const(returns_container())) 的操作,则“完整表达式”会在for 循环开始之前结束。而如果您直接使用了returns_container(),则临时的生命周期将扩展到整个for 循环。最好提前防止人们犯这个错误。
    • std::as_const() 对于选择集合的const 重载特别有用。鉴于std::map&lt;int,int&gt; mm[0]as_const(m)[0] 完全不同。
    • @YSC as_const(m)[0] 格式不正确,是这个意思吗?
    【解决方案2】:

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

    【讨论】:

    • “更好的名字是std::protect”+1。这比大多数实际解释更能说明问题。
    • 自此视频发布以来,我看到了投票率的上升:“C++ Weekly - Ep 291 - Start Using as_const” (youtube.com/watch?v=w996YXhkpkE)
    猜你喜欢
    • 2016-03-14
    • 1970-01-01
    • 1970-01-01
    • 2018-01-07
    • 2021-11-11
    • 1970-01-01
    • 2019-06-09
    • 2011-03-16
    • 1970-01-01
    相关资源
    最近更新 更多