Search code examples
c++c++11language-lawyerdecltype

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


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


Solution

  • 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;
    };