如何将 lambda 用作模板参数,C++ 中的默认值

How to use lambda as template argument with default value in C++?

本文关键字:参数 C++ 默认值 lambda      更新时间:2023-10-16

我想做一件简单的事情:

void DoUntil(auto predicate = [] { return false; });

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

template <typename P>
void DoUntil(P predicate = [] { return false; });

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

错误:调用 ...
注意:候选模板被忽略:无法推断模板参数"P">

如果我确实在没有参数的情况下调用函数,编译器无法从默认参数推断类型:

int main() { DoUntil(); }

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

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

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

void DoUntil() ;
template <typename P>
void DoUntil(P predicate) ;

无参数版本可以简单地调用模板版本,其中包含要用作默认谓词的 lambda:

void DoUntil() { DoUntil([] { return false; }); }

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

template <typename T>
void Foo(T t = 3);

需要的是使用 <typename T = int> 指定T的默认类型。

如 WhiZTiM 的回答中所述,涉及 lambda 函数的情况的默认类型必须使用 decltype 推导。这当然是因为 lambda 具有只有编译器知道的唯一类型。

lambda 是没有默认构造函数的匿名类型(当然,如果可用,您可以使用其复制/移动构造函数(。如果你必须走lambda路,你可以做到:

namespace detail{ auto predicate = [] { return false; }; }
template <typename P = decltype(detail::predicate)>
void DoUntil(P pred = detail::predicate);

而不是试图摆弄羊草。你可以走老路:

namespace detail{
    struct DefaultPredicate{ bool operator()() const { return false; } };
}
template <typename P = detail::DefaultPredicate>
void DoUntil(P predicate = P{});

或者更好的是凯尔斯特兰德回答。