C++ Riddle - Mar-22, 2022

It is well perceived that the use of auto for declaring variables is overall a good practice, deducing the proper type and allowing for easy refactoring.
Though, auto is just a syntactic sugaring, in case it deduces the same type you would be using.
However, if auto would deduce a different type from the type that you would be using (for good or for bad) then things may become interesting.

Bring two examples where auto may deduce a different type than the type the user may use:

  • one example showing auto to be more efficient (i.e. rescue you from inefficiency)
  • another example showing auto to be less efficient (i.e. user selected type might be better)

Note: auto is still syntactic sugaring, so both examples could have used the same type deduced by auto or decide on the type that we actually need and cast to it and still use auto. So we are mainly looking for examples where this is not done and the type deduced by auto is not the same as the one that you use.

2 Likes

This reminds me of something I actually seen in a production code once, when someone decided to take the “auto all the things” to extreme:

auto index = (uint)0;

I told them to change that…

for the first, one may argue that a generic lambda in the context of some std:: algorithm with key/value container, where the std::pair key is const K having auto, is better than std::pair<key, value> while the actual one is std::pair<const key, value>

for the second, I see a lot of issues with people trying to do this:
Foo& getFoo();

auto foo = getFoo(); // and they think that auto is deduced as Foo&, which is not.

other things you had in mind?

auto does what needed sometimes not what you would expect - I do not know which example I like more

Example1

template<typename ContainerType, typename IndexType>                // C++14
decltype(auto) my_find(ContainerType&& container, IndexType&& index) {
  return std::forward<ContainerType>(container)[std::forward<IndexType>(index)];
}

In C++14 the decltype(auto) idiom is introduced. Typically its use is to allow auto declarations to use the decltype rules on the given expression. A good example usage of the idiom is a function return type deduction.

Example 2

void fn(auto&& param)    {
...
}

int main()
{
   int a {42};

    fn(a);     // l-value: auto => int&
    fn(a+1);   // r-value: auto => int

    return 0;
}

In this example -
If the argument is an l-value expression then the template parameter is deduced as a reference-to-expression-type
If the argument is an r-value expression then the template parameter is whatever the expression type was (without any cv-qualifiers)
Then we apply reference-collapsing rules.

There are a few auto abuse example but in my opinion the worst one is "auto decrease readability"

for example -

auto r = fn();
fn1(r);

I think this situation needs to be written in one of the following

int r = fn();
fn1(r);

or 

fn(fn1());

Conclusion
Use auto when it enhances code readability and avoid it where ever it obscures the intent of the code.
auto probably deduce the right thing so use it when it fits.

All the above are good and interesting examples.

My examples would be:
auto improving performance - the famous looping over a map example, already mentioned by @kobica See: c++ - Can the use of C++11's 'auto' improve performance? - Stack Overflow
And here is a piece of code showing that.

As for auto hurting performance, that is when you get back a type that doesn’t match a few following calls, and you have few casting instead of one, like in the code below:

const char* getStr(const char* s) {
    return s;
}

void useStr(const MyString& str) {
    std::cout << str << std::endl;
}

int main() {
    std::cout << "With auto" << std::endl;
    auto less_efficient = getStr("less efficient");
    useStr(less_efficient);
    useStr(less_efficient);
    useStr(less_efficient);
    
    std::cout << std::endl << "Without auto" << std::endl;
    MyString more_efficient = getStr("more efficient");
    useStr(more_efficient);
    useStr(more_efficient);
    useStr(more_efficient);
};

Code link for the above example.

1 Like