clang version 5.0.0 (trunk 305664) Target: x86_64-unknown-linux-gnu
以下代码成功编译:
template <int... A> void f() { ([](auto) { if constexpr (A == 0) return 42; else return 3.14; }(0),...); } int main() { f<0,1>(); }
……但是这个没有:
template <int... A> void f() { ([](auto...) { // Variadic lambda if constexpr (A == 0) return 42; else return 3.14; }(),...); // No argument } int main() { f<0,1>(); }
…屈服:
<source>:7:13: error: 'auto' in return type deduced as 'double' here but deduced as 'int' in earlier return statement return 3.14; ^ <source>:3:6: note: in instantiation of function template specialization 'f()::(anonymous class)::operator()<>' requested here ([](auto...) { // Variadic lambda ^ <source>:12:5: note: in instantiation of function template specialization 'f<0,1>' requested here f<0,1>(); ^
我不希望在空参数包和伪参数之间有不同的行为.
是否存在这种差异的原因,或者这是编译器错误?
解决方法
我相信这是一个铿锵的错误.
[dcl.spec.auto]中的规则强调我的:
If the declared return type of the function contains a placeholder type,the return type of the function is deduced from non-discarded
return
statements,if any,in the body of the function ([stmt.if]).[…]
If a function with a declared return type that contains a placeholder type has multiple non-discarded
return
statements,the return type is deduced for each such return statement. If the type deduced is not the same in each deduction,the program is ill-formed.
lambda中的一个或另一个return语句被丢弃(如果constexpr被称为废弃语句,则取非分支),只留下一个非废弃的return语句,因此lambda的返回类型应该简单地从中推断出来.一个遗留下来.
此外,clang还可以这样:
template <int A> void f() { [](auto...) { if constexpr (A == 0) return 42; else return 3.14; }(); } int main() { f<0>(); f<1>(); }
所以这可能与lambdas在pack表达式中的工作方式有一些不良的交互.