与 lambda 尾随 return 类型不一致

Inconsistency with lambda trailing return types

考虑使用 gcc-7.0.0 最新快照的 this 代码:

auto lambda1 = [](auto&& id) -> decltype(id == 10) { return id == 10; };
auto lambda2 = [](auto&& id) -> decltype(auto)     { return id == 10; };

static_assert(!std::experimental::is_detected_v<ResultOfT,decltype(lambda1),std::string>);
//static_assert(!std::experimental::is_detected_v<ResultOfT,decltype(lambda2),std::string>);
// This doesn't even compile!?
auto bb = std::experimental::is_detected_v<ResultOfT,decltype(lambda2),std::string>;

其中 ResultOfT 只是 std::result_of 的包装器。

为什么 lambda1lambda2 在这个意义上不等价?

据我理解lambda2处的decltype(auto)应该只是decltype(id == 10)的缩写形式,但实际上不是,这是什么原因?

这是 GCC 中的错误吗?

通过将表达式放入 return 类型,您允许编译器调用 SFINAE。这意味着如果 id == 10 在模板替换后不是合法表达式,则不会导致编译错误。这允许 is_detected 确定这是否是一个合法的表达式,因此 return 一个基于该确定的值。

但 SFINAE 仅适用于函数的签名。而对于第二种情况,签名是decltype(auto)。 SFINAE 无法进入将 return 表达式拉入签名的函数。因此,如果您尝试使用 id == 10 不合法的类型来实例化此函数,则只有在实例化该函数时才会被捕获。到那时,SFINAE 保护你已经来不及了。

decltype(auto)decltype(expression) 不同。它们相似,但不完全相同。

标准says:

Function templates can use return type deduction. The deduction takes place at instantiation even if the expression in the return statement is not dependent. This instantiation is not in an immediate context for the purposes of SFINAE.

因此 GCC 中没有错误,它遵循标准并且 lambda1 NOT 等同于 lambda2.