C++ 将同类包装类型的元组转换为原始类型的元组
C++ Convert tuple of homogeneous wrapped type to tuple of raw type
我想调用 std::apply()
函数;但是,我无法这样做,因为我使用的 std::tuple
当前已包装。例如:
#include <tuple>
template <class T>
struct wrapped
{
wrapped(T t) : t(t) {}
T t;
};
template <class T, class ... Args>
struct delay_call
{
T(*callback)(Args...);
std::tuple<Args...> params;
delay_call(T(*callback)(Args...), Args ... params) :
callback(callback), params(params...)
{}
T call()
{
return std::apply(callback, params);
}
};
template <class T, class ... Args>
struct delay_call_with_wrap
{
T(*callback)(Args...);
std::tuple<wrapped<Args>...> w_params;
delay_call_with_wrap(T(*callback)(Args...), wrapped<Args> ... w_params) :
callback(callback), w_params(w_params...)
{}
T call()
{
std::tuple<Args...> params; // = w_params.t
return std::apply(callback, actual_params);
}
};
float saxpy(float a, float x, float y)
{
return a * x + y;
}
int main()
{
float a = 1, x = 2, y = 3;
delay_call delay_saxpy(saxpy, a, x, y);
wrapped w_a = 1.f, w_x = 2.f, w_y = 3.f;
delay_call_with_wrap w_delay_saxpy(saxpy, w_a, w_x, w_y);
float result = delay_saxpy.call();
float w_result = w_delay_saxpy.call();
}
delay_call 结构按预期工作;但是,我不确定如何提取每个元组元素的实际值并将其提供给 std::apply()
来执行。
简而言之,对于 delay_call_with_wrap::call
,我如何将 std::tuple<wrapped<Args>...>
转换为 std::tuple<Args...>
?
我会完全避免 std::apply
并通过使用 std::index_sequence
:
解包元组直接调用 callback
template <std::size_t ...I> T call_low(std::index_sequence<I...>)
{
return callback(std::get<I>(w_params).t...);
}
T call()
{
return call_low(std::make_index_sequence<sizeof...(Args)>{});
}
可能不是实践中使用的最佳解决方案,但这里有一个使用可变模板 lambda 来避免 index_sequence
:
template <class T, class ... Args>
struct delay_call_with_wrap
{
T(*callback)(Args...);
std::tuple<wrapped<Args>...> w_params;
delay_call_with_wrap(T(*callback)(Args...), wrapped<Args> ... w_params) :
callback(callback), w_params(w_params...)
{}
T call()
{
auto helper = [this] <class ... Args_> (wrapped<Args_>... args)
{
return callback(args.t...);
};
return std::apply(helper, w_params);
}
};
我们的想法是只提供一个与 std::apply
此处产生的参数相匹配的函数 - 它需要采用 wrapped<Args>...
。从那里开始,在提取包装值的同时扩展包是微不足道的。
我们使用 lambda 是因为 std::apply
需要一个 Callable,所以我们不能只使用另一个成员函数。好吧,我想我们可以 overload operator()
for delay_call_with_wrap
. That would be mildly confusing but at least not limited to C++2a (and missing compiler support) 喜欢模板化的 lambdas。
In short, for delay_call_with_wrap::call
, how would I convert std::tuple<wrapped<Args>...>
to a std::tuple<Args...>
?
在我看来最好避免 std::apply()
使用旧的 std::make_index_sequence
/std::index_sequence
方式(参见 HolyBlackCat 的回答)。
但是,如果你真的想使用 std::apply()
,你可以第一次调用它来解包元组(以获得解包值的元组),然后像往常一样调用。
我的意思是
T call ()
{
auto actual_params = std::apply([](auto ... wt){ return std::make_tuple(wt.t...); },
w_params);
return std::apply(callback, actual_params);
}
或者,在一次调用中,直接
T call()
{
return std::apply(callback,
std::apply([](auto ... wt){ return std::make_tuple(wt.t...); },
w_params));
}
这个解决方案是合理的,恕我直言,如果 w_param
成员是常量,那么您可以一次计算 actual_params
并使其成为 static
我想调用 std::apply()
函数;但是,我无法这样做,因为我使用的 std::tuple
当前已包装。例如:
#include <tuple>
template <class T>
struct wrapped
{
wrapped(T t) : t(t) {}
T t;
};
template <class T, class ... Args>
struct delay_call
{
T(*callback)(Args...);
std::tuple<Args...> params;
delay_call(T(*callback)(Args...), Args ... params) :
callback(callback), params(params...)
{}
T call()
{
return std::apply(callback, params);
}
};
template <class T, class ... Args>
struct delay_call_with_wrap
{
T(*callback)(Args...);
std::tuple<wrapped<Args>...> w_params;
delay_call_with_wrap(T(*callback)(Args...), wrapped<Args> ... w_params) :
callback(callback), w_params(w_params...)
{}
T call()
{
std::tuple<Args...> params; // = w_params.t
return std::apply(callback, actual_params);
}
};
float saxpy(float a, float x, float y)
{
return a * x + y;
}
int main()
{
float a = 1, x = 2, y = 3;
delay_call delay_saxpy(saxpy, a, x, y);
wrapped w_a = 1.f, w_x = 2.f, w_y = 3.f;
delay_call_with_wrap w_delay_saxpy(saxpy, w_a, w_x, w_y);
float result = delay_saxpy.call();
float w_result = w_delay_saxpy.call();
}
delay_call 结构按预期工作;但是,我不确定如何提取每个元组元素的实际值并将其提供给 std::apply()
来执行。
简而言之,对于 delay_call_with_wrap::call
,我如何将 std::tuple<wrapped<Args>...>
转换为 std::tuple<Args...>
?
我会完全避免 std::apply
并通过使用 std::index_sequence
:
callback
template <std::size_t ...I> T call_low(std::index_sequence<I...>)
{
return callback(std::get<I>(w_params).t...);
}
T call()
{
return call_low(std::make_index_sequence<sizeof...(Args)>{});
}
可能不是实践中使用的最佳解决方案,但这里有一个使用可变模板 lambda 来避免 index_sequence
:
template <class T, class ... Args>
struct delay_call_with_wrap
{
T(*callback)(Args...);
std::tuple<wrapped<Args>...> w_params;
delay_call_with_wrap(T(*callback)(Args...), wrapped<Args> ... w_params) :
callback(callback), w_params(w_params...)
{}
T call()
{
auto helper = [this] <class ... Args_> (wrapped<Args_>... args)
{
return callback(args.t...);
};
return std::apply(helper, w_params);
}
};
我们的想法是只提供一个与 std::apply
此处产生的参数相匹配的函数 - 它需要采用 wrapped<Args>...
。从那里开始,在提取包装值的同时扩展包是微不足道的。
我们使用 lambda 是因为 std::apply
需要一个 Callable,所以我们不能只使用另一个成员函数。好吧,我想我们可以 overload operator()
for delay_call_with_wrap
. That would be mildly confusing but at least not limited to C++2a (and missing compiler support) 喜欢模板化的 lambdas。
In short, for
delay_call_with_wrap::call
, how would I convertstd::tuple<wrapped<Args>...>
to astd::tuple<Args...>
?
在我看来最好避免 std::apply()
使用旧的 std::make_index_sequence
/std::index_sequence
方式(参见 HolyBlackCat 的回答)。
但是,如果你真的想使用 std::apply()
,你可以第一次调用它来解包元组(以获得解包值的元组),然后像往常一样调用。
我的意思是
T call ()
{
auto actual_params = std::apply([](auto ... wt){ return std::make_tuple(wt.t...); },
w_params);
return std::apply(callback, actual_params);
}
或者,在一次调用中,直接
T call()
{
return std::apply(callback,
std::apply([](auto ... wt){ return std::make_tuple(wt.t...); },
w_params));
}
这个解决方案是合理的,恕我直言,如果 w_param
成员是常量,那么您可以一次计算 actual_params
并使其成为 static