【问题标题】:Function wont accept Lambda but will accept function pointer函数不会接受 Lambda 但会接受函数指针
【发布时间】:2020-04-27 12:10:51
【问题描述】:

我正在尝试在 C++ 中实现 JavaScript 映射函数,但无法让它接受 lambda。当我使用函数指针但不使用 lambda 时,它可以工作。我知道 lambda 和函数指针是不同的;我只是不明白为什么 foreach 函数很好但 map 函数不行。

非常感谢您的任何帮助。

template<typename T>
struct List {
    void* buffer;

    ...

    void each(void(func)(T))
    {
        for (u32 index = 0; index < size; index += 1)
        {
            func(((T*)buffer)[index]);
        }
    }

    template <typename OutType>
    List<OutType> map(OutType(func)(T))
    {
        List<OutType> list;
        for (u32 index = 0; index < size; index += 1)
        {
            list.push(func(((T*)buffer)[index]));
        }
        return list;
    }
};

使用代码:

i64 addTwo(i32 n)
{
    return (i64)(n + 2);
}

int main()
{
    List<i32> list;
    list.push(4);
    list.push(2);

    // works
    list.each([](i32 num) {
        std::cout << num << std::endl;
    });

    // works
    auto list1 = list.map(addTwo);

    // does not work
    auto list2 = list.map([](i32 n) -> i32 {
        return n + 3;
    });
}

错误输出:

.../main.cpp:53:23: error: no matching member function for call to 'map'
    auto list2 = list.map([](i32 n) -> i32 {
                 ~~~~~^~~
.../list.hpp:86:19: note: candidate template ignored: could not match 'OutType (*)(int)' against
      '(lambda at /home/caleb/opengl-starter/source/main.cpp:53:27)'
    List<OutType> map(OutType(func)(T))
                  ^
1 error generated.

【问题讨论】:

  • lambda 是可调用类型,是的,但它是可调用的,因为它定义了函数调用运算符。
  • 除了这里列出的原因之外,其他许多原因无法按原样编译代码。请创建一个实际的minimal reproducible example
  • 但它们并不相同。第一个返回 int64。第二个 int32。
  • @AndyG 谢谢,我可能会更新它以更容易重现。我只是在想,只要知道我的错误消息,对 lambda 有更多了解的人就可以轻松回答。
  • @MichaelChourdakis 我也尝试过使用相同的类型。这不应该是错误的根源。

标签: c++ lambda functional-programming


【解决方案1】:

你的函数应该只接受一个简单的类型:

template <typename F, typename OutType = std::invoke_result_t<F, T const&>>
auto map(F function) -> List<OutType>
{
    List<OutType> list;
    for (u32 index = 0; index < size; index += 1)
    {
        list.push(function(((T*)buffer)[index]));
    }
    return list;
}

这样,F 可以是 lambda、函数指针或任何其他可以接收 T 的可调用类型。

如果F 将解析为任何其他不能用T 调用的类型,这将是一个替换错误。

Live example

【讨论】:

  • 谢谢,这是我在代码中输入的内容,运行良好。
【解决方案2】:

在这种情况下,您可以将 lambda 强制转换为函数指针:

auto list2 = list.map(+[](i32 n) -> i32 {
    return n + 3;
});

Demo

这只是因为 lambda 不捕获任何东西。在一般情况下,您的模板应该区分函数指针和可调用事物(定义了 operator() 的事物)。

here's a thorough explanation for why prepending + to the lambda works

【讨论】:

    猜你喜欢
    • 2013-06-06
    • 2015-12-05
    • 1970-01-01
    • 2017-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-21
    相关资源
    最近更新 更多