Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't the compiler infer the type of member when using decltype? [duplicate]

I just noticed this behavior in own code, so here is the naive question:

This:

struct A
{
    int get()
    {
        return a;
    }
    int a=1;
};   
int main() {}

Compiles of course fine, although when the declaration of member data lies after the function definition.

But then I don't understand why this:

struct A
{
    auto get() -> decltype(a)
    {
        return a;
    }
    int a=1;
};  

does not compile(*). I have to write this:

struct A
{
    int a=1;
    auto get() -> decltype(a)
    {
        return a;
    }
};  

Is there any language-related reasons why it's not ok, or is it just that the compilers have not implemented that ? I would expect to have the same behavior regardless of the order of the class members.

(*) tested with gcc 6.3 through Ideone.com

like image 299
kebs Avatar asked Dec 12 '18 13:12

kebs


2 Answers

In your first example, A::get is declared, then A::a is declared, and only then (because A is fully declared), A::get is defined. At this point, in A::get, the compiler knows about A::a.

Consider this equivalent form:

struct A
{
    int get();
    int a=1;
};

inline int A::get()
{
    return a;
}

This would not be compilable for you second example:

struct A
{
    auto get() -> decltype(a); // What is "a"?
    int a=1;
};

inline auto A::get() -> decltype(A::a)
{
    return a;
}

The same "order of declaration" has to be respected when you declare types, for example:

struct A
{
    using IntType = int;
    auto get() -> IntType;
    int a=1;
};

You couldn't write like so:

struct A
{
    using IntType = decltype(a);
    auto get() -> IntType;
    int a=1;
};

Also note that this is not limited to return types: parameter types are also part of a function declaration. So this doesn't compile either:

struct A
{
    void f(decltype(a));
    int a=1;
};
like image 79
Nelfeal Avatar answered Sep 18 '22 15:09

Nelfeal


An informal answer if I may: decltype is a red herring.

All parts of a return type need to have already been seen by the compiler on the first pass.

For example,

template <size_t N> struct T{};

struct A
{
    T<sizeof(a)> get()
    {
        return T<sizeof(a)>();
    }
    int a;
};

will also fail, for the same reason: compilation passes if int a; is seen before get().

like image 23
Bathsheba Avatar answered Sep 17 '22 15:09

Bathsheba