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

你离开我真会死。 提交于 2020-12-29 08:52:30

问题


C++11 has given us std::add_const; with C++17, we have a new structure - std::as_const(). The former just tacks a const before the type you provide it with. The second one is a proper (template of a) function, not type trait, which seems to do the same - except for when the type is an rvalue-reference, in which case it cannot be used.

I don't quite understand the motivation for providing std::as_const(). Why do we need it in addition to std::add_const?


回答1:


"Need" is a strong word... std::as_const exists because it's useful, not strictly necessary. Since it's a function rather than a trait, we can use it to "add const" to actual values rather than to types.

More specifically: Suppose I have some variable my_value and I want to treat it as a const, but not copy it. Before C++17 I would need to write:

static_cast<const MyType&>(my_value)

and if I don't want to specify the type explicitly, it would be:

static_cast<std::add_const_t<std::remove_reference_t<decltype(my_value)>> &>(my_value)

or if you want to get down and dirty, and use C-style casting:

(const decltype(my_value) &) (my_value)

all of which are annoying and verbose.

Instead of these, with C++17 now write std::as_const(my_value) and that's all there is to it.

Notes:

  • This function is disabled for rvalue references even though it works just fine for them. The reason is to help you avoid inadvertantly keeping a reference to a temporary past its destruction. As @NicolBolas explains, if you write something like:

    for(auto &x : std::as_const(returns_container())) { /* do stuff with x */ }
    

    then the returned container's lifetime ends before the first iteration of the loop. Very easy to miss!

  • For additional (?) information, consult the official proposition of this utility function: P007R1, by Adam David Alan Martin and Alisdair Meredith.




回答2:


You may want to overload const, no-const and force one or the overloads:

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

template<class T>
void twice(T& t){return t += t;}

You can protect the input by adding const and use the non-modifying overload.

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.

I am not saying it is a good design, it is just to illustrate the point. It is a matter of time to find a more useful case.

A better name for std::as_const could have been std::protect IMO.



来源:https://stackoverflow.com/questions/53450366/what-do-we-need-stdas-const-for

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!