如何通过 std::apply 调用具有定义的第一个参数的可变参数模板函数?
How to call variadic template function with defined first parameter through std::apply?
我对参数包比较陌生,但我想构建一个 class 来接收参数包,收集其中包含的值并将它们启动到另一个函数中。
我有一个 class,它有可变参数模板和一个赋值函数。函数正在从 VARIANT 结构中获取参数。
解包函数:
template <typename...Args>
constexpr void ValuesFromValuesVariant(VARIANT variant, Args&...args)
{
static std::size_t nArgs = sizeof...(Args);
if (!nArgs) return;
auto vArray = GetArray(variant, nArgs);
auto i = 0u;
GetNextItem(vArray, i, args);
}
使用它的Class:
template <class ...Args>
class Receiver
{
using SendFunction = std::function<HRESULT(Args...)>;
using InterruptFunc = std::function<HRESULT()>;
...
virtual HRESULT OnSend(VARIANT params)
{
//Here I'd like to call it with a VARIANT, but I can't for some reason
std::apply(ValuesFromValuesVariant, params, std::tie(arguments)); //std::tie to get refs& to the arguments
HRESULT hr = std::apply(m_Function, arguments);
return hr;
}
private:
InterruptFunc m_InterruptFunc;
SendFunction m_Function;
private:
std::tuple< Args... > arguments;
};
我试过 std::bind 第一个函数参数,但它不能自动预测它接受的参数,
VariantCommunication::ValuesFromValuesVariant<Args>
说明符无效。
要将 apply
与元组之外的参数一起使用,您可以在函子中捕获它:
std::apply([&](auto&... args){ ValuesFromValuesVariant(params, args...); }, arguments);
或将额外参数连接到元组:
std::apply(&ValuesFromValuesVariant, std::tuple_cat(std::tie(params), arguments));
因为ValuesFromValuesVariant
通过左值引用获取它的参数,首先你需要从arguments
创建左值引用的元组。然后你可以使用 tuple_cat
连接从 params
和前一个创建的元组:
它可能看起来像:
virtual HRESULT OnSend(VARIANT params)
{
// [1] make tuple of references to arguments
auto makeRef = [](auto & ... args){ return std::forward_as_tuple(args...); };
auto t1 = std::apply( makeRef , arguments);
// [2] make tuple from params
auto t2 = std::forward_as_tuple(params);
std::apply(ValuesFromValuesVariant<Args...>, std::tuple_cat( t1, t2 ) );
HRESULT hr{1};
return hr;
}
首先,std::tie(arguments)
不会创建 std::tuple
对 arguments
元素的引用。它将做的是创建一个 std::tuple
,它具有一个引用 arguments
的单个元素。要获取对元组的引用的元组,需要一个适配器,如
template<typename... Elems, std::size_t... Indicies>
auto make_reference_tuple_impl(std::tuple<Elems...>& tuple, std::index_sequence<Indicies...> indices)
{
return std::tuple<Elems&...>{std::get<Indicies>(tuple)...};
}
template<typename... Elems>
auto make_reference_tuple(std::tuple<Elems...>& tuple)
{
return make_reference_tuple_impl(tuple, std::make_index_sequence<sizeof...(Elems)>{});
}
然后你需要做的是将 params
和 std::tie
一起变成引用的元组,然后你可以将这些元组与 std::tuple_cat
组合在一起。您还需要将 ValuesFromValuesVariant
包装在 lambda 中,因为您可以将函数模板传递给 std::apply
。把所有这些放在一起会给你的代码看起来像
virtual HRESULT OnSend(VARIANT params)
{
auto param_ref = std::tie(params);
auto arg_ref = make_reference_tuple(arguments);
auto concat = std::tuple_cat(param_ref, arg_ref);
std::apply([](auto...& args){ValuesFromValuesVariant(args);}, concat);
HRESULT hr = std::apply(m_Function, arguments);
return hr;
}
我对参数包比较陌生,但我想构建一个 class 来接收参数包,收集其中包含的值并将它们启动到另一个函数中。
我有一个 class,它有可变参数模板和一个赋值函数。函数正在从 VARIANT 结构中获取参数。
解包函数:
template <typename...Args>
constexpr void ValuesFromValuesVariant(VARIANT variant, Args&...args)
{
static std::size_t nArgs = sizeof...(Args);
if (!nArgs) return;
auto vArray = GetArray(variant, nArgs);
auto i = 0u;
GetNextItem(vArray, i, args);
}
使用它的Class:
template <class ...Args>
class Receiver
{
using SendFunction = std::function<HRESULT(Args...)>;
using InterruptFunc = std::function<HRESULT()>;
...
virtual HRESULT OnSend(VARIANT params)
{
//Here I'd like to call it with a VARIANT, but I can't for some reason
std::apply(ValuesFromValuesVariant, params, std::tie(arguments)); //std::tie to get refs& to the arguments
HRESULT hr = std::apply(m_Function, arguments);
return hr;
}
private:
InterruptFunc m_InterruptFunc;
SendFunction m_Function;
private:
std::tuple< Args... > arguments;
};
我试过 std::bind 第一个函数参数,但它不能自动预测它接受的参数,
VariantCommunication::ValuesFromValuesVariant<Args>
说明符无效。
要将 apply
与元组之外的参数一起使用,您可以在函子中捕获它:
std::apply([&](auto&... args){ ValuesFromValuesVariant(params, args...); }, arguments);
或将额外参数连接到元组:
std::apply(&ValuesFromValuesVariant, std::tuple_cat(std::tie(params), arguments));
因为ValuesFromValuesVariant
通过左值引用获取它的参数,首先你需要从arguments
创建左值引用的元组。然后你可以使用 tuple_cat
连接从 params
和前一个创建的元组:
它可能看起来像:
virtual HRESULT OnSend(VARIANT params)
{
// [1] make tuple of references to arguments
auto makeRef = [](auto & ... args){ return std::forward_as_tuple(args...); };
auto t1 = std::apply( makeRef , arguments);
// [2] make tuple from params
auto t2 = std::forward_as_tuple(params);
std::apply(ValuesFromValuesVariant<Args...>, std::tuple_cat( t1, t2 ) );
HRESULT hr{1};
return hr;
}
首先,std::tie(arguments)
不会创建 std::tuple
对 arguments
元素的引用。它将做的是创建一个 std::tuple
,它具有一个引用 arguments
的单个元素。要获取对元组的引用的元组,需要一个适配器,如
template<typename... Elems, std::size_t... Indicies>
auto make_reference_tuple_impl(std::tuple<Elems...>& tuple, std::index_sequence<Indicies...> indices)
{
return std::tuple<Elems&...>{std::get<Indicies>(tuple)...};
}
template<typename... Elems>
auto make_reference_tuple(std::tuple<Elems...>& tuple)
{
return make_reference_tuple_impl(tuple, std::make_index_sequence<sizeof...(Elems)>{});
}
然后你需要做的是将 params
和 std::tie
一起变成引用的元组,然后你可以将这些元组与 std::tuple_cat
组合在一起。您还需要将 ValuesFromValuesVariant
包装在 lambda 中,因为您可以将函数模板传递给 std::apply
。把所有这些放在一起会给你的代码看起来像
virtual HRESULT OnSend(VARIANT params)
{
auto param_ref = std::tie(params);
auto arg_ref = make_reference_tuple(arguments);
auto concat = std::tuple_cat(param_ref, arg_ref);
std::apply([](auto...& args){ValuesFromValuesVariant(args);}, concat);
HRESULT hr = std::apply(m_Function, arguments);
return hr;
}