`if constexpr`,里面lambda,内包扩展 - 编译bug?

Que*_*tin 7 c++ language-lawyer compiler-bug clang++ c++17

clang version 5.0.0 (trunk 305664)
Target: x86_64-unknown-linux-gnu
Run Code Online (Sandbox Code Playgroud)

以下代码成功编译:

template <int... A>
void f() {
    ([](auto) {
        if constexpr (A == 0)
            return 42;
        else
            return 3.14;
    }(0), ...);
}

int main() {
    f<0, 1>();
}
Run Code Online (Sandbox Code Playgroud)

......但是这个没有:

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>();
}
Run Code Online (Sandbox Code Playgroud)

...屈服:

<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>();
    ^
Run Code Online (Sandbox Code Playgroud)

我不希望在空参数包和伪参数之间有不同的行为.

是否存在这种差异的原因,或者这是编译器错误?

Bar*_*rry 3

我相信这是一个 clang bug。

[dcl.spec.auto] 中的规则是,强调我的:

如果函数声明的返回类型包含占位符类型,则从函数体 ([stmt.if]) 中的未丢弃 语句(如果有)推导出函数的返回类型。return

[...]

如果声明的返回类型包含占位符类型的函数具有多个非丢弃 return语句,则将为每个此类返回语句推导返回类型。如果每次推导中推导的类型不相同,则该程序是格式错误的。

lambda 中的一个或另一个return语句被丢弃(其中未采用的分支if 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>();
}
Run Code Online (Sandbox Code Playgroud)

因此,这可能与 lambda 在包表达式中的工作方式存在一些不良交互。