大佬教程收集整理的这篇文章主要介绍了gcc 接受并拒绝带有嵌套泛型 lambda 的此代码,为什么?,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
根据 Godbolt 的 Compiler Explorer(参见 demo),以下代码使用 GCC(10.2 和主干)编译并输出 3628800,但无法使用 Clang(11.0.1 和主干)编译。在这两种情况下,都使用 -std=c++17
。它还可以使用 MSVC 19 进行编译,但不能使用其他编译器进行编译。为什么会这样,谁的行为是正确的?
#include <iostream>
int main()
{
std::cout << [](auto f) { return f(f); }(
[](auto& h) {
return [&h](auto n) {
if (n < 2)
return 1;
else
return n * h(h)(n - 1);
};
})(10) << std::endl;
}
此外,如果我将 auto n
替换为 int n
或将 if-else 替换为三元运算符 (return n < 2 ? 1 : (n * h(h)(n - 1));
),即使 GCC 和 MSVC 也会拒绝代码。
该程序格式错误,无需诊断,因此两种实现(实际上,任何实现)都是正确的。违反的规则是 [temp.res.general]/6.4:
紧接其定义的模板的假设实例化将由于不依赖于模板参数的构造而格式错误
这里的模板是最里面的 operator()
:它使用了直接包含 operator()
的特化(使用它作为成员的闭包类型作为模板参数),它有一个推导返回类型。这里的“立即跟随”(仍然)在应该从中推断出该类型的返回语句中,因此实例化将由于仅 h(h)
而格式错误,它不涉及 的模板参数那个模板(即,n
的类型)。
GCC 和 MSVC 在最终实例化之前不会对推导的返回类型进行语义检查(使用 int
表示 10),此时返回类型是已知的:它只是最里面的 lambda。但是,如果最里面的 lambda 不是通用的,则检查会在包含 operator()
的实例化期间进行,并且会发生相同的错误。
这种行为差异可以从一个更简单的例子中看出:
auto g();
template<class T> auto f(T X) {return g()-x;}
此时Clang已经拒绝了,但是GCC接受了,也许后面是
auto g() {return 1;}
int main() {return f(1);}
以上是大佬教程为你收集整理的gcc 接受并拒绝带有嵌套泛型 lambda 的此代码,为什么?全部内容,希望文章能够帮你解决gcc 接受并拒绝带有嵌套泛型 lambda 的此代码,为什么?所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。