簡體   English   中英

Lambda /任意Arity函數並將捕獲作為函數參數

[英]Lambda/function of arbitrary arity and with captures as a function argument

在我的C ++程序中,我經常需要在一個小的有限域上,根據函數的所有可能值構建函數值的向量。 例如,如下所示:

int q = 7;
vector<int> GFq;
for (int x = 0; x < q; x++) GFq.push_back(x);

auto P = [q](int x, int y) -> int { return (x*x+y) % q; };
auto Q = [q](int x, int y) -> int { return (x+2*y) % q; };
auto f = [q,P,Q](int x1, int y1, int x2, int y2) 
        -> int {return (P(x1,y1) + Q(x2,y2)) % q; }

vector<int> table;
for (int x1: GFq) for (int y1: GFq) for (int x2: GFq) for (int y2: GFq)
    table.push_back(f(x1,y1,x2,y2));

這種模式在我的代碼中經常被重復,以至於我自然希望使其成為一個函數。 所以我需要這樣的東西:

template<typename F>  // not sure if I need to use templates
vector<int> tabulate(int q, F f) {
    // run through values 0..q-1 for all arguments of f
    // and store the values of f to the resulting vector
}

一些問題/問題:

  • 我希望能夠將任意函數傳遞給tabulate()包括具有不同Arity的函數(即f(x)f(x,y)等)
  • 我想構造“動態”傳遞的函數,包括使用其他函數(與在第一個代碼段中從PQ構造f方式相同)
  • 如果我設法通過這樣的功能,我怎么可以運行在所有可能的參數的循環f (即0..q-1為每個參數)內tabulate()

我希望能夠將任意函數傳遞給tabulate(),包括具有不同含義的函數(即f(x),f(x,y)等)

使tabulate模板,該模板接受任意類型的對象作為函數。

我想構造“動態”傳遞的函數,包括使用其他函數(與在第一個代碼段中從P和Q構造f的方式相同)

您可以將lambda直接用作函數參數。

如果我設法傳遞了這樣一個函數,如何在tabulate()中對f的所有可能參數(即,每個參數的0..q-1)運行循環?

用偽代碼:

params = {0, ..., 0};

while (1)
{
    // Call function with `params` here.

    int i = 0;
    for (i = 0; i < params.size(); i++)
    {
        params[i]++;
        if (params[i] == q)
            params[i] = 0;
        else
            break;
    }
    if (i == params.size())
        break;
}

實際上,您需要將參數存儲在std::array (或std::tuple ,如下面的代碼所示)中,並使用std::apply來使用這些參數調用函數。


完整的實現:

#include <cstddef>
#include <iostream>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>

template <typename T, typename ...P, std::size_t ...I>
bool increment_tuple_impl(T q, std::tuple<P...> &t, std::index_sequence<I...>)
{
    auto lambda = [&](auto index) -> bool
    {
        auto &elem = std::get<index.value>(t);
        elem++;
        if (elem == q)
        {
            elem = 0;
            return 0;
        }
        else
        {
            return 1;
        }
    };

    return (lambda(std::integral_constant<std::size_t, I>{}) || ...);
}

template <typename T, typename ...P>
bool increment_tuple(T q, std::tuple<P...> &t)
{
    return increment_tuple_impl(q, t, std::make_index_sequence<sizeof...(P)>{});
}

template <typename T, typename F, std::size_t MaxArity, typename ...P>
auto tabulate_impl(T q, F &&f)
{
    if constexpr (!std::is_invocable_v<F, P...>)
    {
        static_assert(sizeof...(P) < MaxArity, "Invalid function.");
        return tabulate_impl<T, F, MaxArity, P..., T>(q, std::forward<F>(f));
    }
    else
    {
        using return_type = std::invoke_result_t<F, P...>;
        std::vector<return_type> vec;
        std::tuple<P...> params{};
        do
        {
            vec.push_back(std::apply(f, params));
        }
        while (increment_tuple(q, params));
        return vec;
    }
}

template <typename T, typename F>
auto tabulate(T q, F &&f)
{
    constexpr int max_arity = 8;
    return tabulate_impl<T, F, max_arity, T>(q, std::forward<F>(f));
}

int main()
{
    auto v = tabulate(3, [](int x, int y){return x*10 + y;});

    // Prints `0 10 20 1 11 21 2 12 22`.
    for (auto x : v)
        std::cout << x << ' ';
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM