2017-05-11 59 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