提问人:Danny 提问时间:9/9/2022 最后编辑:The Dreams WindDanny 更新时间:9/9/2022 访问量:97
如何将参数包中的可调用对象与数组中的相应元素作为参数匹配?
How to match callable objects out of parameter pack to corresponding element in an array as argument?
问:
例如,假设我有以下内容:
template<typename ...FunctionTypes>
static void MainFunction(FunctionTypes... functions)
{
constexpr Uint32_t NumFunctions= sizeof...(FunctionTypes);
std::array<double, NumFunctions> myArray;
double arg1 = 4.2;
int arg2= 9;
for_each_tuple(myArray, FigureOutThisPart(myFunctions, arg1, arg2)...);
}
Where 采用元组或大小数组以及要应用于每个元组条目的函数。这部分很难实现,但有效!它的定义如下:for_each_tuple
N
N
namespace detail {
template <typename Tuple, std::size_t ...Indices, typename ...FunctionTypes>
constexpr void for_each_tuple_impl(Tuple&& tuple, std::index_sequence<Indices...>, FunctionTypes&&... functionsIn) {
std::tuple<FunctionTypes...> functions = std::tie(functionsIn...);
using swallow = int[];
(void)swallow{
1, // Make sure array has at least one element
(std::get<Indices>(functions)(std::get<Indices>(std::forward<Tuple>(tuple))), void(), int{})...
};
}
}
template <typename Tuple, typename ...Functions>
void for_each_tuple(Tuple&& tuple, Functions&&... f) {
constexpr std::size_t N = std::tuple_size<std::remove_reference_t<Tuple>>::value;
static_assert(N == sizeof...(Functions), "Need one function per tuple entry");
detail::for_each_tuple_impl(
std::forward<Tuple>(tuple),
std::make_index_sequence<N>{},
std::forward<Functions>(f)...);
}
这个想法是我有一组 ,每个 都在不同的条目上操作。中的每个函数都将 、 和当前数组条目作为参数。myFunctions
myArray
myFunctions
arg1
arg2
我的目标是能够传入并进入每个值,以便这些值可以在当前数组条目的操作中使用。有没有一种理智的方法可以做到这一点?理想情况下,我希望解决方案是一个 constexpr,以便所有内容都可以在编译时得到解决。arg1
arg2
myFunctions
答:
4赞
Quimby
9/9/2022
#1
我认为这样的事情可以工作:
#include <array>
#include <functional>
template<typename ...FunctionTypes>
constexpr void MainFunction(FunctionTypes... functions)
{
constexpr auto NumFunctions= sizeof...(FunctionTypes);
std::array<double, NumFunctions> myArray{};//Zero-init for now.
double arg1 = 4.2;
int arg2= 9;
std::size_t i=0;
(std::invoke(functions, arg1,arg2, myArray[i++]),...);
}
#include <iostream>
void foo(double a1, int a2, int a){
std::cout<<"Called foo("<<a1<<','<<a2<<','<<a<<")\n";
}
int main()
{
MainFunction(foo,foo);
return 0;
}
折叠表达式需要 C++17,逗号需要序列点。
它可以在编译时进行评估:
constexpr void bar(double a1, int a2, int a){
}
int main()
{
constexpr auto x = (MainFunction(bar,bar),1); // Force compile-time evaluation.
return 0;
}
评论
1赞
Danny
9/9/2022
哦,这太棒了!选中我所有的框,不需要改变我所拥有的太多东西。非常感谢!
0赞
Quimby
9/9/2022
@Danny 请注意,通话中只能有一个表达式。不能使用单个变量跨两个数组编制索引,因为函数参数的计算顺序未指定,并且增量使该 UB。在这种情况下,只需使用两个单独的变量。i
2赞
The Dreams Wind
9/9/2022
#2
我只是在一开始就用函子制作一个元组,并将元组的一个元素与数组的相应元素相匹配:
template<std::size_t I, typename E, typename ...F, typename ...Args>
constexpr void apply(const std::array<E, sizeof...(F)>& elements,
const std::tuple<F...>& functions,
Args... args) {
std::get<I>(functions)(std::get<I>(elements), args...);
}
template<std::size_t ...I, typename E, typename ...F, typename ...Args>
constexpr void for_each(std::index_sequence<I...>,
const std::array<E, sizeof...(I)>& elements,
const std::tuple<F...>& functions,
Args... args) {
(apply<I>(elements, functions, args...),...);
}
template<typename ...F>
constexpr static void MainFunction(F... functors)
{
constexpr std::size_t size = sizeof...(F);
constexpr std::array<double, size> elements{};
constexpr double arg1 = 4.2;
constexpr int arg2 = 9;
for_each(std::make_index_sequence<size>(),
elements,
std::forward_as_tuple(functors...),
arg1, arg2);
}
客户端代码将如下所示:
void function(double val, double arg1, int arg2) {
std::cout << arg1 + arg2 + 8 * val << std::endl;
}
int main() {
MainFunction(function, [](double val, double arg1, double arg2) {
std::cout << val / arg1 + arg2 << std::endl;
});
return 0;
}
只要参数函数是 ,实现也是:constexpr
constexpr
template<typename ...F>
constexpr static auto MainFunction(F... functors) { ... return elements; }
constexpr void function(double val, double arg1, int arg2) { ... }
int main() {
// Retrieves the constexpr elements array from the function
constexpr auto val = MainFunction(function, [](double, double, int){ ... });
}
1赞
Fureeish
9/9/2022
#3
您可以使用 std::bind_front
构造一个具有占位符参数的函数,这是一个更接近您最初预期的解决方案。然而,这有一个缺点,即不能在上下文中运行:constexpr
template <std::size_t N, typename T, typename... Functions>
auto for_each_tuple(std::array<T, N> const& array, Functions... functions) {
auto index = 0uz;
(std::invoke(functions, array[index++]), ...);
}
template<typename ...FunctionTypes>
static void MainFunction(FunctionTypes... functions)
{
constexpr std::uint32_t NumFunctions= sizeof...(FunctionTypes);
std::array<double, NumFunctions> myArray{};
double arg1 = 4.2;
int arg2= 9;
for_each_tuple(myArray, std::bind_front(functions, arg1, arg2)...);
}
auto main() -> int {
auto print_thrice = [](double d1, int i2, double arr) {
std::cout << d1 << ' ' << i2 << ' ' << arr << '\n';
};
MainFunction(print_thrice, print_thrice, print_thrice);
}
评论