2017-05-11 97 views
2

這些演示函數不應該是gcc 中的無限循環,因爲條件運算符應僅評估活動部分。C++中的條件運算符錯誤?

它們在Visual Studio 2015中正確編譯,但在g ++ 6.3中給出了無限遞歸錯誤編譯錯誤。我錯過了什麼?

template <int n> 
constexpr int infinite_loop_error(){ 
    return (n) ? infinite_loop_error<n - 1>() : 0; 
} 

template <int n> 
constexpr int infinite_loop_error_2(){ 
    if (n) return infinite_loop_error_2<n - 1>(); 
    else return 0; 
} 

void main() { 
    infinite_loop_error<3>(); 
    infinite_loop_error_2<3>(); 
} 
+0

標準中的任何事情都說這不應該是無限遞歸嗎?如果在C++ 17(我認爲?),也許constexpr將是一個解決方案。 – Kevin

+0

我假設你知道你可以通過創建功能模板的特化解決問題。凱文: –

+0

:是的! 「如果constexpr」聲明(與clang一起測試)適用於此。感謝您的建議 – programmer

回答

7

這是MSVC中的一個錯誤,你的程序不應該編譯。您正在混合運行時遞歸和編譯時遞歸。

雖然節目只應評估在運行時三元表達的一方面,編譯器仍然需要爲三元表達的雙手(和的if條件兩個分支)生成代碼。代碼生成過程中程序失敗,因爲編譯器找不到可以停止的點。 MSVC「成功」,因爲它太早應用優化,侵犯了as-if規則。

您需要使用template specialization as a stopping condition

template <int n> 
constexpr int infinite_loop_error(){ 
    return (n) ? infinite_loop_error<n - 1>() : 0; 
} 

template <> 
constexpr int infinite_loop_error<0>(){ 
    return 0; 
} 

template <int n> 
constexpr int infinite_loop_error_2(){ 
    if (n) return infinite_loop_error_2<n - 1>(); 
    else return 0; 
} 

template <> 
constexpr int infinite_loop_error_2<0>(){ 
    return 0; 
} 

int main() { 
    infinite_loop_error<3>(); 
    infinite_loop_error_2<3>(); 
} 

相反實例化自定義,這將使它進一步遞歸infinite_loop_error<0>,編譯器會使用您爲它提供和編譯時遞歸正確停止的定義。

+0

非常棒的回答。非常感謝。 – programmer