Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does auto return type deduction work with not fully defined types?

Consider the following:

template<typename Der>
struct Base {
    // NOTE: if I replace the decltype(...) below with auto, code compiles
    decltype(&Der::operator()) getCallOperator() const {
        return &Der::operator();
    }
};

struct Foo : Base<Foo> {
    double operator()(int, int) const {
        return 0.0;
    }
};

int main() {
    Foo f;
    auto callOp = f.getCallOperator();
}

I want to create a member function in CRTP base class with a return type depending on signature of the operator() in the derived class. However decltype(&Der::operator()) fails to compile; The operator() member function in Foo is not visible. I assume that this is because the base class template is instantiated before Foo is fully defined.

Surprisingly, if I place auto for the return type it compiles. I assumed that auto would make the compiler deduce the return type from the function body and fail - because the body uses the not fully defined Foo type.

This behavior is the same for both MSVC 2015.3 and Clang 3.8

Why did the code start to work with auto? Does auto type deduction somehow "delay" the instantiation? Or use a different context than a hand-written return type expression?

like image 232
Michał W. Urbańczyk Avatar asked Jul 12 '16 10:07

Michał W. Urbańczyk


People also ask

What is automatic type deduction?

With auto type deduction enabled, you no longer need to specify a type while declaring a variable. Instead, the compiler deduces the type of an auto variable from the type of its initializer expression.

Can auto be a return type?

In C++14, you can just use auto as a return type.


1 Answers

Your guess is correct. A deduced return type is not actually deduced until the signature of the function is needed. This means that it will be deduced in the context of the call to getCallOperator, at which point Foo is fully defined.

This is specified in 7.1.6.4p12:

Return type deduction for a function template with a placeholder in its declared type occurs when the definition is instantiated even if the function body contains a return statement with a non-type-dependent operand.

like image 107
Sebastian Redl Avatar answered Oct 27 '22 00:10

Sebastian Redl