Reputation: 884
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.
Upvotes: 4
Views: 570
Reputation: 302862
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;
};
Upvotes: 4
Reputation: 473397
Ever notice how you can call inline-defined member functions from inside of other member functions, even if the callee is farther down the class than the caller? The reason that works is because the compiler takes inlined definitions of member functions and moves the definitions to the bottom of the class, right after the }
part. So you effectively have an implicit forward declaration.
This is not true for type aliases like using
declarations. These declarations exist exactly where they are in the class; they cannot reference declarations or definitions that come later in the class.
Since the return value of your function cannot be deduced by the declaration alone, and the actual definition (the thing needed to deduce the return value) lives at the end of the class, your using
alias fails to compile. There's not much you can do about this besides declare the function's return value directly. Or declare the type alias as having the desired type, then have the function use that alias.
Upvotes: 5
Reputation: 25526
Could an intermediate typedef help? Something like:
#include <vector>
struct Test
{
template <typename T>
using MySimplerType = std::vector<T>;
template <typename T>
static auto GetVector() { return MySimplerType<T>(); }
using VecInt = MySimplerType<int>;
VecInt x;
};
Upvotes: 0