Я хочу иметь возможность передавать произвольную функцию для табулирования (), включая функции разной арности (т. Е. F (x), f (x, y) и т. Д.)
Сделать tabulate
шаблон, который принимает объекты произвольных типов в качестве функций.
Я хочу создать функцию, которую я передаю «на лету», включая использование других функций (так же, как и для fпостроен из P и Q в первом фрагменте кода
Вы можете использовать лямбда-выражение непосредственно в качестве параметра функции.
если мне удастся передать такую функцию, какможно запустить цикл для всех возможных аргументов f (т. е. 0..q-1 для каждого из своих аргументов) внутри tabulate ()?
В псевдокоде:
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 << ' ';
}