Search code examples
c++autotype-deduction

C++ auto type deduction when declaring variables without initialisation


I actually really like the automatic type deduction in C++, where I can have an arbitrarily complex return type from a function, but not worry about what the type is when calling the function.

In other words, something like:

std::vector<std::map<std::string, std::string>> getCollection() { ... }
auto myMapArray = getCollection();

However, this appears to work only if the compiler can deduce the type, such as when it's initialised from the function.

I often find myself in a situation where I just want a default-constructed variable of the correct type (usually a class member variable) and it pains me to have to do:

std::vector<std::map<std::string, std::string>> getCollection();
std::vector<std::map<std::string, std::string>> m_collection;

in this case. But I know of no other way to avoid the long type names, other than using typedef or the more modern using:

typedef std::vector<std::map<std::string, std::string>> VecOfMaps;
using VecOfMaps = std::vector<std::map<std::string, std::string>>;
:
VecOfMaps m_collection;

It appears it would be useful to allow type deduction of a variable as if it were something returned from a function, such as with:

std::vector<std::map<std::string, std::string>> getCollection() { ... }
auto m_collection = asif(getCollection);

You wouldn't need to provide parameters since all overloads are required to return the same type. So my questions are really:

  • Is there a better way than type aliasing to do this?
  • Are the any obvious shortcomings to the asif solution (it would have to allow for templated functions but that should just be a minor extension)?

Solution

  • Concerning your comment:

    It appears it would be useful to allow type deduction of a variable as if it were something returned from a function, such as with:

    std::vector<std::map<std::string, std::string>> getCollection() { ... }
    auto m_collection = asif(getCollection);
    

    It appears to me that asif() sounds somehow like decltype().

    In this case, it is the return type of function which is required, hence it should be

    decltype(getCollection()) m_collection;
    

    I must admit that I'm not that experienced with the practical use of decltype() in daily business and fiddled myself a bit (out of curiosity), ending up with:

    #include <iostream>
    #include <map>
    #include <string>
    #include <vector>
    
    auto func() { return std::vector<std::map<std::string, std::string>>(); }
    
    struct Class {
      typedef decltype(func()) VarType;
      VarType var;
    };
    
    int main()
    {
      Class obj;
      std::cout << "type of Class::var: " << typeid(obj.var).name() << '\n';
    }
    

    The output of that is:

    type of Class::var: St6vectorISt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_St4lessIS6_ESaISt4pairIKS6_S6_EEESaISD_EE

    Live Demo on coliru

    So far, so good.


    Can I do a decltype(fn()) variable; without a type alias?

    #include <iostream>
    #include <map>
    #include <string>
    #include <vector>
    
    auto func() { return std::vector<std::map<std::string, std::string>>(); }
    
    struct Class {
      decltype(func()) var;
    };
    
    int main()
    {
      Class obj;
      std::cout << "type of Class::var: " << typeid(obj.var).name() << '\n';
    }
    

    Output:

    type of Class::var: St6vectorISt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_St4lessIS6_ESaISt4pairIKS6_S6_EEESaISD_EE

    Live Demo on coliru

    I must admit that it was one of the samples in the linked decltype() documentation which made me sure about this.

    Furthermore, I would like to mention that decltype() is (similar like e.g. sizeof) a compile-time type-only evaluation. Hence, it even works if there is no implementation of func() available at all:

    #include <iostream>
    #include <map>
    #include <string>
    #include <vector>
    
    std::vector<std::map<std::string, std::string>> func();
    
    struct Class {
      decltype(func()) var;
    };
    
    int main()
    {
      Class obj;
      std::cout << "type of Class::var: " << typeid(obj.var).name() << '\n';
    }
    

    Output:

    type of Class::var: St6vectorISt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_St4lessIS6_ESaISt4pairIKS6_S6_EEESaISD_EE

    Live Demo at coliru


    It looks like I can do the former but I want to make sure it's a standard thing and not just a gcc extension.

    As far as I know, decltype() is in fact a C++ standard feature (since C++11 and the fact that it is mentioned in cppreference.com would count as "proof" to me).

    Aside from this, I used the last sample to check it with

    • clang 10.0.0 -std=c++11
    • gcc 10.1 -std=c++11
    • msvc v19.24 /std:c++14 (/std:c++11 is not an available option.)

    All passed this check on CompilerExplorer.