【问题标题】:Getting the function prototype of a lambda获取 lambda 的函数原型
【发布时间】:2017-11-25 05:44:39
【问题描述】:

我正在创建一个通用 C++ EventEmitter。它基于Node.js EventEmitter

template <typename ...Args>
int16_t EventEmitter::addListener(uint32_t eventId, std::function<void(Args...)> cb)
{
    ...
}

template <typename... Args>
void EventEmitter::emit(uint32_t eventId, Args... args)
{
    ...
}

它按预期工作(我可以使用不同的原型注册侦听器)。例如:

auto handler = [](int n) { ... };

listener.addListener(0, std::function<void(int)>(handler));

但我不想每次添加一个(有些参数超过5个)时都将整个监听器原型输入std::function&lt;...&gt;,然后我决定创建一个宏:

#define STDFUNC(fn) std::function<decltype(fn)>(fn)

问题是当我尝试将它与 lambdas 一起使用时:decltype(handler) 不是void(int),而是class lambda []void (int n)-&gt;void,会产生错误:

(Clang 3.7.1) -> 错误:未定义模板的隐式实例化 'std::_Get_function_impl

我正在挠头以获得没有 lambda 限定符的原型,但我被困住了。任何帮助将不胜感激。

【问题讨论】:

  • 你为什么要添加具有不同签名的监听器?
  • @n.m.每个事件都有自己的参数,emit方法是:template &lt;typename... Args&gt; void emit(uint32_t eventId, Args... args)
  • 多么有趣的问题。你知道,lambda 类型必须声明一个operator ()。你想要的是那个签名。此外,使用预处理器宏是邪恶的,如果可能的话,你应该避免它。在 STDFUNC 的情况下,您可以轻松定义一个模板函数来执行此操作,并且您应该这样做。
  • @Omnifarious 完全正确,但据我所知,lambda 对象被语言“抽象”了。关于宏,我会按照你的建议定义一个模板,一旦我弄清楚了。谢谢。
  • 你的问题和这个不同吗? stackoverflow.com/questions/11893141/…

标签: c++ templates


【解决方案1】:

这是一个为任意 lambda 生成函数对象的小程序:

#include <functional>
#include <type_traits>

template <typename R, typename... A>
class build_func_type
{
 public:
   using type = ::std::function<R(A...)>;
};

template <typename R, typename C, typename... A>
typename build_func_type<R, A...>::type mem_func_to_func( R(C::*)(A...) const)
{
   return nullptr;
}

template <typename T>
decltype(mem_func_to_func(&T::operator ())) lambda_to_fp(T le)
{
    using func_t = decltype(mem_func_to_func(&T::operator ()));
    return func_t{le};
}

int test()
{
   auto foo = [](int x) -> int { return x * x; };
   auto ftype = lambda_to_fp(foo);
   return ftype(5);
}

它使用函数mem_func_to_func 自动推断lambda 的operator () 的类型。然后它使用build_func_type 模板从lambda 的operator () 类型的组件中构建一个函数类型。我可能在 build_func_type 中使用了构造函数,并为此依赖 C++17 构造函数类型推导。

然后lambda_to_fp 将采用 lambda,使用 mem_func_to_func 从指向 lambda 的 operator () 成员函数的指针创建指向适当函数类型的指针。然后它创建一个适当类型的::std::function,从函数指针的类型构造该类型。然后它用 lambda 初始化它并返回它。

【讨论】:

  • lambda_to_fp 中没有auto 返回类型是否可能?似乎 Clang 3.7.1(至少使用默认设置)无法编译它,因为它是 C++14 扩展。
  • @karliwson - 我不确定。这样做会很棘手。你可以给 clang -std=c++14。 :-) 我会考虑一下如何解决这个问题。你基本上明白它是怎么回事吗?我的意思是一般的代码。
  • 那种。你得到了 lambda 的 operator() 并使用一些魔法来提取它的原型并用它创建一个 std::function。顺便说一句,-std=c++14 在 Clang 3.7.1 中不可用(我在 Windows 上使用 LLVM)。
  • @karliwson - 在那里,我修好了。
  • lambda 函数 operator () 的地址类型将是 R (C::*)(A...) const 其中 R 是返回类型,C 是 lambda 本身的类型,而 A... 是所有参数类型的列表。诀窍是将其转换为::std::function 类型。它必须使用函数来完成,因为编译器只会推断函数的模板参数。在 C++17 中,编译器将为构造函数推导出模板参数,但您甚至不需要 C++14。 :-)
猜你喜欢
  • 2021-06-06
  • 2012-10-24
  • 1970-01-01
  • 2023-03-18
  • 2016-07-25
  • 1970-01-01
  • 2016-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多