Der Rückgabetyp eines Lambdas kann durch den Rückgabewert abgeleitet werden. Warum kann eine Funktion nicht verwendet werden?

75
#include <iostream>

int main(){

    auto lambda = [] {
        return 7;
    };

    std::cout << lambda() << '\n';

}

Dieses Programm kompiliert und druckt 7.
Der Rückgabetyp des Lambda wird basierend auf dem Rückgabewert von 7 zum ganzzahligen Typ abgeleitet.


Warum ist das mit normalen Funktionen nicht möglich?

#include <iostream>

auto function(){
    return 42;
}

int main(){

    std::cout << function() << '\n';
}

Fehler: Die Funktion 'function' verwendet den Typbezeichner 'auto' ohne nachfolgenden Rückgabetyp

Trevor Hickey
quelle
5
Bereits verfügbar in VS2013 Nov CTP. Es ist eine C ++ 14-Funktion, die bereits verfügbar ist. Es ist eine großartige Hilfe für Vorlagenfunktionen mit unordentlichen Rückgabetypen.
CodeAngry

Antworten:

77

C ++ 14 verfügt über diese Funktion . Sie können es mit neuen Versionen von GCC testen oder klirren, indem Sie das -std=c++1yFlag setzen.

Live Beispiel

Darüber hinaus können Sie in C ++ 14 für Ihre Funktion auch den Rückgabewert mithilfe der Semantik ableiten decltype(auto)(der sich decltype(auto)als der von Variablen decltypewiderspiegelt).

Ein Beispiel wäre das für Weiterleitungsfunktionen, für das decltype(auto)besonders nützlich ist:

template<typename function_type, typename... arg_types>
decltype(auto) do_nothing_but_forward(function_type func, arg_types&&... args) {
    return func(std::forward<arg_types>(args)...);
}

Mit der Verwendung von decltype(auto)ahmen Sie den tatsächlichen Rückgabetyp nach, funcwenn Sie mit den angegebenen Argumenten aufgerufen werden. Es gibt keine Duplizierung von Code mehr im nachfolgenden Rückgabetyp, was in C ++ 11 sehr frustrierend und fehleranfällig ist.

Mark Garcia
quelle
3
Warum decltype(auto)und nicht nur auto?
Bindestrich
25

Dies ist nur eine Einschränkung der Art und Weise, wie die Sprache erstellt wurde und sich weiterentwickelt hat. Im kommenden C ++ 14-Standard kann der Rückgabetyp einer Funktion in einigen Kontexten abgeleitet werden, wenn auch nicht in allen. Es gibt Komplikationen, wenn mehrere Rückgabeanweisungen vorhanden sind.

Darüber hinaus weisen abgeleitete Rückgabetypen andere Probleme auf. Beispielsweise kann der Rückgabetyp einer Vorlagenfunktion nicht in einem SFINAE- Kontext verwendet werden. Um den Typ ableiten zu können, muss der Compiler die Funktionsvorlage instanziieren, was nach dem Ersetzen geschieht . Das Nettoergebnis ist, dass die Funktion zwar in naher Zukunft verfügbar sein wird, ich sie jedoch vermeiden würde, wenn Sie den Typ selbst bereitstellen können.

David Rodríguez - Dribeas
quelle
5
"Dies ist nur eine Einschränkung der Art und Weise, wie die Sprache erstellt wurde und sich weiterentwickelt hat." - Natürlich ist es +1 allein dafür.
Christian Rau
6

Es ist immer noch nicht da. Es wird in C ++ 1y / C ++ 14 sein. Schauen Sie sich diesen Link an

Hitesh Vaghani
quelle
5

Ich vermute, dass es wahrscheinlich daran liegt, dass vom Typ abgeleitete Lambdas nicht rekursiv sein können .

Warum ist das wichtig? Denn wenn ein vom Typ abgeleitetes Lambda rekursiv sein könnte (mit "vom Typ abgeleitet" meine ich, wo der Name der Variablen vom Typ ist auto), könnte sein Rückgabetyp möglicherweise von sich selbst abhängen - und obwohl dies manchmal möglich ist, es zu lösen schwieriger zu implementieren als "einfache" Typinferenz. Ich bin mir nicht mal sicher, ob es immer lösbar ist (ist es im allgemeinen Fall entscheidbar?). Wenn Funktionen jedoch Typinferenz unterstützen würden, müsste dieses Problem behoben werden, sodass sie wahrscheinlich aus diesem Grund nur ausgeschlossen werden.

user541686
quelle
1
Kannst du mehr erklären?
Bryan Chen
1
Dies ist kein Unterschied zwischen Lambdas und Funktionsdefinitionen. Sogar einfache Objekte können eine zirkuläre Abhängigkeit angeben auto x = x * 2;. In allen Fällen ist es einfach verboten.
Potatoswatter
1
@Mehrdad Es ist verboten. Gleich wie ein selbstreferenzielles Lambda. Das ist mein Punkt.
Potatoswatter
2
Lambdas und Funktionen dürfen rekursiv sein, und die Variableninitialisierung darf selbstreferenziell sein, ist jedoch autobei zyklischer Abhängigkeit schlecht ausgebildet.
Potatoswatter
2
Ihre Behauptung in dieser Antwort ist, dass die Rekursion möglicherweise ein Problem in Verbindung mit darstellt auto. Meine Antwort ist, dass dies wahr ist, aber sie haben das Problem bereits gelöst, indem sie Ihnen einfach verboten haben, das Falsche zu tun. Es gibt keinen Grund, warum sich Funktionen von Lambdas unterscheiden sollten, und in C ++ 14 werden sie es nicht sein.
Potatoswatter