如何在C++中使用lambda作为模板参数和默认值?

aby*_*s.7 10 c++ lambda c++17

我想做一件简单的事:

void DoUntil(auto predicate = [] { return false; });
Run Code Online (Sandbox Code Playgroud)

显然这不起作用 - 我必须使用模板参数:

template <typename P>
void DoUntil(P predicate = [] { return false; });
Run Code Online (Sandbox Code Playgroud)

但是这个陈述也不起作用 - Clang给出了一个错误:

错误:没有匹配函数用于调用...
注意:候选模板被忽略:无法推断模板参数'P'

如果我没有参数调用函数,编译器无法从默认参数中推断出类型:

int main() { DoUntil(); }
Run Code Online (Sandbox Code Playgroud)

我不想以std::function<>任何方式使用.

我的问题还有其他可能的解决方案吗?

Kyl*_*and 8

使用函数重载而不是默认参数功能.创建一个非模板函数,除模板函数外不带任何参数:

void DoUntil() ;

template <typename P>
void DoUntil(P predicate) ;
Run Code Online (Sandbox Code Playgroud)

无参数版本可以简单地使用您要用作默认谓词的lambda来调用模板版本:

void DoUntil() { DoUntil([] { return false; }); }
Run Code Online (Sandbox Code Playgroud)

原始方法的问题在于,您尝试通过指定默认参数值来提供默认模板特化,但不指定默认模板类型.即使没有涉及lambdas,以下也不会起作用,因为T没有默认类型,即使t有默认值:

template <typename T>
void Foo(T t = 3);
Run Code Online (Sandbox Code Playgroud)

我们需要的是指定一个默认的类型T使用<typename T = int>.

如WhiZTiM的回答所述,涉及lambda函数的案例的默认类型必须使用推导出来decltype.这当然是因为lambdas具有只有编译器才知道的唯一类型.


Whi*_*TiM 5

Lambda是没有默认构造函数的匿名类型(原因是,您可以使用其复制/移动构造函数(如果可用))。如果必须采用lambda方式,则可以执行以下操作:

namespace detail{ auto predicate = [] { return false; }; }

template <typename P = decltype(detail::predicate)>
void DoUntil(P pred = detail::predicate);
Run Code Online (Sandbox Code Playgroud)

而不是尝试摆弄lambda。您可以采用旧的好方法:

namespace detail{
    struct DefaultPredicate{ bool operator()() const { return false; } };
}

template <typename P = detail::DefaultPredicate>
void DoUntil(P predicate = P{});
Run Code Online (Sandbox Code Playgroud)

还是Kyle Strand 回答的更好。