Функция не примет лямбда, но примет указатель на функцию - PullRequest
3 голосов
/ 09 января 2020

Я пытаюсь реализовать функцию отображения JavaScript в C ++, но не могу заставить ее принять лямбду. Это работает, когда я использую указатель на функцию, но не с лямбда-выражением. Я понимаю, что лямбда и указатель на функцию разные; Я просто не понимаю, почему функция foreach хороша, а функция карты - нет.

Любая помощь, которую вы будете очень благодарны.

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.

Ответы [ 2 ]

6 голосов
/ 09 января 2020

Ваша функция должна просто принимать простой тип:

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 может быть лямбда-выражением, указателем на функцию или любым другим вызываемым типом, который может получить T.

Если F преобразуется в любой другой тип, который не может быть вызван с T, это будет ошибкой замещения.

Живой пример

5 голосов
/ 09 января 2020

В этом случае вы можете преобразовать лямбду в указатель функции:

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

Демо

Это работает только потому, что лямбда ничего не захватывает. В общем случае ваш шаблон должен различать guish между указателями на функции и вызываемыми объектами (вещи с определенным operator()).

Вот подробное объяснение, почему стоит добавить + на лямбда работает

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...