【问题标题】:How can I restrict lambda signatures in C++17 template arguments?如何限制 C++17 模板参数中的 lambda 签名?
【发布时间】:2020-09-23 13:48:41
【问题描述】:

假设我有两个函数接收不同的 lambda 类型作为参数:

template<typename F>
void func1(F&& lambda) {
    // lambda must be [](unsigned int) -> short
}

template<typename F>
void func2(F&& lambda) {
    // lambda must be [](const vector<string>&) -> void
}

如何在 C++17 中限制这些 lambda 签名,以完全匹配我在每种情况下的需要?

【问题讨论】:

  • 这有帮助吗? stackoverflow.com/a/50859251
  • 您想特别限制 lambdas 的签名还是允许任何可以使用特定参数集调用的给定可调用对象类型?
  • @pasbi 可能是,但它似乎没有验证返回类型。我很难处理给定的示例,它没有编译。
  • @NicolBolas 我想限制 lambda 的签名,包括返回类型。
  • @rodrigocfd:嗯,你不能专门限制 lambda 的签名,因为没有任何机制可以用来区分 lambda 和任何其他可调用的用户定义类型.

标签: c++ templates lambda constraints c++17


【解决方案1】:

C++20 之前的:

template<typename F, typename = std::enable_if_t<
    std::is_invocable_v<F, unsigned int>
>>
void  func1( F &&lambda ) {
    // lambda must be [](unsigned int) -> short
}

C++20:

template<typename F>
requires std::is_invocable_v<F, unsigned int>
void  func1( F &&lambda ) {
    // lambda must be [](unsigned int) -> short
}

如果您还想验证返回类型,请使用 std::is_invocable_r_v。

[编辑]

... 使用 std::is_invocable_r_v

template<typename F, typename = std::enable_if_t<
    std::is_invocable_r_v<short, F, unsigned int>
>>
void  func1( F &&lambda ) {
    // lambda must be [](unsigned int) -> short
}

【讨论】:

  • 你介意用is_invocable_r_v写一个例子,验证返回类型吗?
  • 您完全忽略了这一点,即这将接受可以使用这些参数调用的每个函子(而不仅仅是 具有 那些参数类型)。这是一个至关重要的区别。现在,当然,这最终可能是更好的选择(检查确切的签名是一个有点有限的用例),但省略对差异的解释就是疏忽。
  • 返回类型被验证为“可转换”,对吗? (我的意思是,在这种情况下,我的 lambda 可以返回 intshort,因为它是可转换的。)
【解决方案2】:

立即想到的一种方法是利用std::function 及其推导指南。使用 CTAD,可以自动推断某些类型的函子(其中包括非泛型 lambda)的签名。它看起来像这样

template<typename F>
auto func1(F&& lambda) 
  -> std::enable_if_t<std::is_same_v<decltype(std::function{std::forward<F>(lambda)}), std::function<short(unsigned)>>> {
    // lambda must be [](unsigned int) -> short
}

std::function{std::forward&lt;F&gt;(lambda)} 是一个函数转换表达式,它尝试将参数转换为 std::function,其模板参数被推导出来。如果推演成功,我们可以得到一个类型与std::function&lt;short(unsigned)&gt;进行比较。有了这些,我们就可以使用标准库中常用的 SFINAE 实用程序来约束 func1

但是请注意,这并不仅仅将函数模板限制为 lambdas,CTAD 成功并匹配参数列表的任何函子都将被接受。

【讨论】:

  • 它似乎有效,但我的大脑现在正在融化。我以前从未见过返回-&gt; 的函数,在哪里可以了解它?
  • @rodrigocfd - 这只是一个trailing return type。它是 C++ 引入的一种声明风格。它适用于所有功能,因此即使auto main() -&gt; int {} 也是有效的。我只是更喜欢在返回类型上执行 SFINAE 的代码,因为对我个人而言,它似乎更具可读性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-16
  • 2018-10-12
  • 2016-10-27
  • 2018-07-17
  • 2019-06-09
  • 1970-01-01
相关资源
最近更新 更多