简体   繁体   中英

what is the purpose of using auto when declaring variable with static_cast<>()?

Scott Meyers in his "Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14" discusses use of auto in different contexts. He makes a point that sometimes auto deducts incorrect type because normally, a developer would use (possibly unconsciously) implicit conversion like here:

std::vector<bool> vec = {true, false};
bool a = vec[0]

while using auto like that:

std::vector<bool> vec = {true, false};
auto a = vec[0]

would yield a to be std::vector<bool>::reference so the author proposes to cast it before assignment:

auto a = static_cast<bool>(vec[0])

and I cannot understand why would I use auto and static_cast<> in this way if I can simply count on implicit conversion. I figured that maybe it is to highlight the fact that there is a conversion going on (to note it explicitly) but it still looks like an overkill to me. What would be the advantage of such solution?

Cheers!

There are a number of cases where static_cast can help reduce both compiler ambiguities and also reader ambiguities when used with auto .

Specifically, when considering std::vector<bool> in the example, I can think of two such cases:

  • If this were passed to a function template that deduces the argument, you would probably rather decltype(a) to be a bool rather than some std::__vector_bool_reference_wrapper type, or
  • If a were passed to a function with a signature that accepts a bool& or bool* , you would want this to be the correct type -- since implicit conversions will not occur

The above cases apply to anything that may have implicit conversions, not just bool /reference-wrapper.

Additionally, cases get more interesting with other types.

Pointers:

nullptr is of type decltype(nullptr) which is also aliased as std::nullptr_t . This is not any type T* . Which means you can't write code like:

auto p = nullptr;
...
p = &a; // compile-error!

But instead would need:

auto p = static_cast<T*>(nullptr);
...
p = &a; // works!

Unintentional Promotions

Unintentional promotion can produce unexpected bugs. If code is using auto and is relying on integer overflow, without being explicit about types, it is possible to unintentionally produce integer promotion -- which can prevent that overflow from occurring. This can produce subtle bugs in some code.

The same is likely possible with float / double promotion, though I'm having a harder time thinking of a case where such a case would be negative.

Unintended promotions can also cause compile-failures if the result is being passed to a function that expects a reference or pointer to T of a different type than the promoted type is (similar to the vector<bool> example above).


I'm sure other cases exist where static_cast is significant when used with auto , but in general the cases that come to mind deal with the strict typing that comes with overload resolution and template type deduction.

Other than that, there may also be cases where static_cast just helps the general readability of complex functions that use a lot of auto

Take that as a premise: You want to use auto as much as possible, then

std::vector<bool> vec = {true, false};
auto a = vec[0];

will do the unexpected, while:

auto a = static_cast<bool>(vec[0]);

will get you a bool . I don't think the point here is to say: "Use static_cast together with auto as much as possible". But rather: "If you want to use auto almost always, then sometimes you have to add a static_cast "

...in this way if I can simply count on implicit conversion...

In this case yes, but then you are not using auto . Also consider the case when it wasn't you who used auto . Lets say you are given a lambda defined as:

auto foo = [](auto x){};

You cannot change its signature, hence you need to use a static_cast if you want to call it with vec[0] and get the right type deduced.

Also consider that if you do follow AAA (almost always auto) then you do want do declare all variables as auto . This helps to never forget to initialize a variable. If you fall back to

bool a = vec[0];

when needed, then that defeats the whole point of applying AAA in the first place. You want to be consistent and not choose auto vs explicit type depending on the initializer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM