c++c++17return-type-deduction

Deducing the return type of an inline static member function in class definition


I'm trying to create an alias to a return type after an inline function definition to store a member variable. I simplified my situation below (the real type I want to alias is much uglier to type than vector, and the real function more complicated than a one-liner.)

#include <vector>
using namespace std;
struct Test {
    template <typename T>
    static auto GetVector() { return vector<T>(); }

    using VecInt = decltype(GetVector<int>());
    VecInt x;
};

However, clang gives me the following error on the using VecInt line:

error: function 'GetVector' with deduced return type cannot be used before it is defined.

gcc also gives me a similar error. Strangely, this compiles, although it's not useful in my case:

#include <vector>
using namespace std;
struct Test {
    template <typename T>
    static auto GetVector() { return vector<T>(); }

    void dummy() {
        using VecInt = decltype(GetVector<int>());
        VecInt x;
    }
};

Is there a way for me to alias after an inline definition? Alternatively, I can move the GetVector() function on top of the struct, and the code will compile. However, I want to contain it there.


Solution

  • Member function bodies are a complete-class context, meaning that the class is regarded as complete there. Within the body of a member function, name lookup can find any other member function or data member of typedef - whether it was declared before the function or after.

    Since GetVector() has a placeholder type, it needs to wait until the class is complete before instantiating the body and deducing the return type.

    But alias declarations are not complete-class contexts. You need to figure out what VecInt is at that point, without having the class being complete yet. Since GetVector() needs the class to complete first, this just can't work.

    You'll either need to (a) explicitly specify the return type of GetVector(), (b) explicitly specify VecInt, or (c) move GetVector() out of this class (whether making it a free function or moving it to a base class):

    #include <vector>
    
    struct TestBase {
        template <typename T>
        static auto GetVector() { return std::vector<T>(); }
    };
    
    struct Test : TestBase {
        using VecInt = decltype(GetVector<int>());
        VecInt x;
    };