Lambda作为默认参数失败

tem*_*boy 17 c++ c++17

我使用以下代码获得了最新版本的clang和gcc的错误:

int main() {
    auto lambda = [] (auto = [] {}) {};
    lambda();
}
Run Code Online (Sandbox Code Playgroud)

Clang给出错误:

prog.cc: In function 'int main()':
prog.cc:3:12: error: no match for call to '(main()::<lambda(auto:1)>) ()'
     lambda();
            ^
prog.cc:2:35: note: candidate: template<class auto:1> main()::<lambda(auto:1)>
     auto lambda = [] (auto = [] {}) {};
                                   ^
prog.cc:2:35: note:   template argument deduction/substitution failed:
prog.cc:3:12: note:   couldn't deduce template parameter 'auto:1'
     lambda();
            ^
Run Code Online (Sandbox Code Playgroud)

为什么这会失败?

Dan*_*rey 22

类型推导auto不考虑默认参数.

  • 普通模板也是如此.我发现在代码转换方面考虑通常会有所帮助.例如,还用于理解类定义中的成员函数的定义. (5认同)
  • "auto"的类型推导对于模板是相同的(减去`initializer_list`事物).您不能通过其默认参数推断出模板参数的类型. (3认同)

Den*_*rim 11

由于lambdas是仿函数的,因此问题在于模板函数无法auto在此默认上下文中推导出模板参数().

通过考虑这些语句,lambda可以简化为functor结构级别:

§5.1.2/ 3 [expr.prim.lambda]

lambda表达式的类型(也是闭包对象的类型)是一个唯一的,未命名的非联合类类型[...]

§5.1.2/ 5 [expr.prim.lambda]

[...]对于通用lambda,闭包类型有一个公共内联函数调用操作符成员模板(14.5.2),其template-parameter-list包含一个发明的类型模板参数,用于lambda参数中每次出现的auto -declaration-clause,按照出现的顺序.[...]

因此,lambda的类型等同于这个functor类型:

struct unnamed
{
    template<typename Auto1>
    auto operator()(Auto1 = []{})
    {
    }
};
Run Code Online (Sandbox Code Playgroud)

然后你的用法相当于:

int main() {
    auto lambda = unnamed();
    lambda();
}
Run Code Online (Sandbox Code Playgroud)

根据§14.8.2.5/ 5 [temp.deduct.type]中的Auto1规定,无法在此上下文中推断出类型:

未推断的上下文是:

[...]

- 在函数参数的参数类型中使用的模板参数,该参数具有在正在进行参数推断的调用中使用的默认参数.