lambda的常见类型转换和稍后引用的函数

时间:2012-12-29 09:37:49

标签: c++ c++11 lambda

为什么第二个例子不起作用?有没有办法让第二个例子工作,同时仍然将lambda或函数类型转换为一个媒介,以便稍后引用?

// Types I'm using
typedef void (*ANY_FUNC)(...);
typedef void (*VOID_FUNC)();

此作品

void call_void( VOID_FUNC func) {
    ((ANY_FUNC)func)();
};

// ...

call_void([]() { /* do something */ });

这不是

template <typename fn>
void call_any( fn func ) {
    ((ANY_FUNC)func)();
};

// ...

call_any([]() { /* do something */ });

请忽略这样一个事实,即您永远不需要使用第二个示例现在的样子。它仅用于演示(相对代码)。

这两个示例都使用函数指针而不是lambdas。

4 个答案:

答案 0 :(得分:2)

直接

As long as you are declaring a template you can just use the incoming function object。此外,您应该将函数参数声明为引用而不是按值:

template <typename fn>
void call_any(fn&& func) {
    func();
};

如果你想用参数调用函数,你可以这样做:

template <typename fn, typename... Args>
void call_any_many(fn&& func, Args&&... args) {
    func(std::forward<Args>(args)...);
};

用法示例:

int main ()
{
    call_void([]() { std::cout << "Hello, void World!" << std::endl; });
    call_any([]() { std::cout << "Hello, any World!" << std::endl; });
    call_any_many([](int x) { std::cout << "Hello, any many World-" << x << "!" << std::endl; }, 1234);

    return 0;
}

但如果您打算存储一些函数指针而不是直接调用它们,我建议您使用std::function标题中的<functional>。您可以在此处查看一些信息和示例:http://en.cppreference.com/w/cpp/utility/functional/function

例如:

#include <iostream>
#include <functional>

int main ()
{
    std::function<void()> anyf = []() { std::cout << "Hello, any World!" << std::endl; };
    std::function<void(int)> intf = [](int x) { std::cout << "Hello, any many World-" << x << "!" << std::endl; };

    anyf();
    intf(1234);

    return 0;
}

答案 1 :(得分:0)

我不认为他们中的任何一个真的有效,除非是偶然的某些编译器。

与lambda的区别在于它可以转换为函数指针,但它不是一个。模板版本会发现此差异,fn不会推断为VOID_FUNC

答案 2 :(得分:0)

Lambdas可以隐式转换为函数指针(但只有当它们没有捕获任何东西时),所以只需将call_any的参数更改为函数指针:

void call_any(ANY_FUNC func)
{
    (*func)();
}

您需要使用适当类型的lambda调用它:

call_any([](...) { /* ... */ });

但是可变长度的参数列表(也称为varargs)很糟糕,因为它们是非类型安全的,因为它们可以获得。与函数指针相同:它们是非面向对象的。您应该考虑一种替代机制,可能涉及可变参数模板和多态(虚拟方法)

答案 3 :(得分:0)

第一个是将lambda转换为具有相应参数和返回类型的函数指针,然后将其转换为vararg函数,而第二个尝试将lambda直接转换为vararg函数(即没有相应参数的函数)类型)。

第一个示例中的两个转换是允许*,但第二个中的单个转换不是。

* 请注意,用于在函数指针类型之间转换的强制转换符号最终像reinterpret_cast一样工作,它表示:“函数指针可以显式转换为函数指针通过指向函数类型(8.3.5)的函数调用函数的效果与函数定义中使用的类型不同是未定义的。“因此,第一个示例代码具有未定义的行为。