Ich experimentiere mit conexpr Funktionen in C++ 14. Der folgende Code, der die Fakultäts Werke berechnet wie erwartet:C++ 14: abgeleitete (automatische) Rückgabetypen von constexpr mit ternären Ausdrücken
template <typename T>
constexpr auto fact(T a) {
if(a==1)
return 1;
return a*fact(a-1);
}
int main(void) {
static_assert(fact(3)==6, "fact doesn't work");
}
, wenn es kompiliert wird, wie mit Klirren folgt:
> clang++ --version
clang version 3.5.0 (tags/RELEASE_350/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
> clang++ -std=c++14 constexpr.cpp
Allerdings, wenn ich die fact
Definition ändern, um den ternären ?
Operator zu verwenden:
template <typename T>
constexpr auto fact(T a) {
return a==1 ? 1 : a*fact(a-1);
}
erhalte ich den folgenden Compiler-Fehler:
> clang++ -std=c++14 constexpr.cpp
constexpr.cpp:12:31: fatal error: recursive template instantiation exceeded maximum depth of
256
return a==T(1) ? T(1) : a*fact(a-1);
... snip ...
constexpr.cpp:16:19: note: in instantiation of function template specialization 'fact<int>'
requested here
static_assert(fact(3)==6, "fact doesn't work");
das Problem behoben ist, wenn ich ausdrücklich den Rückgabetyp T-Zustand (statt Auto für die Verwendung des Rückgabetyp abzuleiten)
template <typename T>
constexpr T fact(T a) {
return a==1 ? 1 : a*fact(a-1);
}
Wenn ich die Template-Parameter entfernen, wird das Muster (die ternäre Version wiederholt schlägt fehl, und die if
Version funktioniert)
// this works just fine
constexpr auto fact(int a) {
if(a==1)
return 1;
return a*fact(a-1);
}
während dies nicht gelingt
constexpr auto fact(int a) {
return a==1 ? 1 : a*fact(a-1);
}
mit dem folgenden Fehler
> clang++ -std=c++14 constexpr.cpp
constexpr.cpp:16:25: error: function 'fact' with deduced return type cannot be used before it
is defined
return a==1 ? 1 : a*fact(a-1);
^
constexpr.cpp:15:16: note: 'fact' declared here
constexpr auto fact(int a) {
^
constexpr.cpp:20:26: error: invalid operands to binary expression ('void' and 'int')
static_assert(fact(3)==6, "fact doesn't work");
~~~~~~~^ ~
2 errors generated.
Was ist hier los?
die if-Version zwei return-Anweisungen hat. Verwendet der Compiler/standard eine Art fauler Bewertung, bei der nur die Rückgabeanweisung im if-Block berücksichtigt wird, wenn a == 1? Sonst hätten wir das gleiche Problem mit beiden Versionen. – bcumming
Danke @Praetorian. Ich kann es selbst nachschlagen (obwohl ich kein Sprachanwalt bin). – bcumming
@Praetorian Es ist nicht das Gegenteil von dem, was Sie zuvor behauptet haben. Der Rückgabetyp wird für jede return-Anweisung abgeleitet, aber sobald er für * any * return-Anweisungen abgeleitet ist, ist der Rückgabetyp bekannt und kann als Teil der Ableitung späterer return-Anweisungen verwendet werden. Der Grund, warum Ihr Beispiel mit 'template' fehlschlägt, ist, weil 'fact 's Rückgabetyp, der bekannt ist, nichts über 'fact ' 's Rückgabetyp sagt, aber es ist' fact ', das' fact ' im OP-Code aufruft . –
hvd