Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why can't auto infer the type when the return type is specified?

MRE:

std::vector<std::string> someFunction() {
    auto vec;
    return vec;
}

What’s stopping "auto" from inferring the type of vec as std::vector<std::string>?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

From your question, it appears that you believe that since the compiler knows the return type, it should be able to deduce that the variable being returned must be of that return type. But, that is not how the compiler works!

Rather, the compiler knows the return type, so it tries to implicitly cast vec to that known return type upon returning. But, it doesn’t know how to perform this implicit cast because it doesn’t know the original type of vec.

That’s just how the compiler works. Specifying a return type doesn’t change the type of vec, it just ensures that the compiler tries to implicitly cast vec to that type.

So, with your code, you get this error when compiled with the GNU g++ compiler as C++17:

main.cpp: In function ‘std::vector<std::__cxx11::basic_string<char> > someFunction()’:
main.cpp:15:5: error: declaration of ‘auto vec’ has no initializer
   15 |     auto vec;
      |     ^~~~

To make my point, check this out. This code compiles! I am forcing a reinterpret cast from an int to a std::vector<std::string>:

Run this code online here: https://onlinegdb.com/RaDEmExfF

#include <iostream>
#include <string>
#include <vector>

std::vector<std::string> someFunction() 
{
    int i;

    // return by value (copy)
    return *((std::vector<std::string>*)(&i));
}

int main()
{
    std::vector<std::string> vector = someFunction();
    
    return 0;
}

Since that makes no sense and is totally undefined behavior, however, I get a run-time crash (on Linux x86-64):

terminate called after throwing an instance of 'std::bad_array_new_length'
  what():  std::bad_array_new_length

Just remember, the return type doesn’t specify the source type of vec. Rather, it simply enforces the type that vec gets implicitly cast to when it is returned.

Going further: memory pools

Check this out. To make things even weirder for you, this is a totally fine and valid program now, with well-defined behavior.

I simply used an array of bytes as a memory pool to statically construct a std::vector<std::string> object from within a memory pool of 100 bytes. I could have used a memory pool of ints too, as int[25].

#include <iostream>
#include <string>
#include <vector>

std::vector<std::string> someFunction() 
{
    // undefined behavior check
    constexpr uint16_t NUM_BYTES = 100;
    static_assert(NUM_BYTES >= sizeof(std::vector<std::string>));
    
    uint8_t memory_pool[NUM_BYTES];
    
    // return by value (copy)
    return *((std::vector<std::string>*)(memory_pool));
}

int main()
{
    std::vector<std::string> vector = someFunction();
    vector.push_back("hello ");
    vector.push_back("world");
    
    std::cout << vector[0] << vector[1] << "\n";

    return 0;
}

Now it is a perfect program and runs just fine. The output is:

hello world

One more valid version of this function that now has optimal memory usage:

std::vector<std::string> someFunction() 
{
    uint8_t memory_pool[sizeof(std::vector<std::string>)];
    
    // return by value (copy)
    return *((std::vector<std::string>*)(memory_pool));
}

Or, just skip the memory pool and use the proper type in the first place:

std::vector<std::string> someFunction() 
{
    std::vector<std::string> vec;
    
    return vec;
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading