与lambda尾随返回类型不一致



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

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在这个意义上不等价?

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

这是GCC中的一个bug吗?

通过将表达式放入返回类型中,您允许编译器调用SFINAE。这意味着,如果id == 10不是模板替换后的合法表达式,则不会导致编译错误。这允许is_detected判断该表达式是否合法,并根据判断返回一个值。

但是SFINAE只作用于函数的签名。对于第二种情况,签名是decltype(auto)。SFINAE无法进入函数将返回表达式拉入签名中。因此,如果你试图用一个id == 10不合法的类型实例化这个函数,这只会在函数实例化时被捕获。到那时,SFINAE已经来不及保护你了。

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

标准规定:

函数模板可以使用返回类型演绎。这个推论需要放置在实例化处,即使表达式在返回语句中不是依赖的。此实例化不在立即上下文中

所以在GCC中没有bug,它遵循标准,lambda1而不是等同于lambda2

最新更新