问题描述
我有一个带有N个参数的函数
I have a function which takes N parameters
void func(int, double, char);
和具有匹配类型的元组
std::tuple<int, double, char> tuple;
根据此stackoverflow问题,我能够展开元组并调用该函数.
As per this stackoverflow question, I am able to expand the tuple and call the function.
再进一步,我的元组包含一个类模板的多个实例:
Taking it a step further, my tuple contains multiple instances of a class template:
template<typename T>
struct Foo;
std::tuple<Foo<int>, Foo<double>, Foo<char>>
Foo
具有成员函数Foo<T>::get()
,该成员函数返回类型为T
的值.
Foo
has a member function, Foo<T>::get()
which returns a value of type T
.
根据此stackoverflow答案,我在下面的工作代码中展开了元组,并在每个元素上调用了element.get()
,最终将结果传递给了func
.
As per this stackoverflow answer,I have below working code which expands the tuple and calls element.get()
on each element, ultimately passing the result to func
.
不幸的是,我已经硬编码了对element.get()
的呼叫.
The unfortunate thing is that I've hard-coded the call to element.get()
.
(这是我正在寻求的帮助)
(This is what I'm looking for help to do)
是否可以将其设为通用?也就是说,要传递哪个成员函数来调用apply
,并因此将其作为通用工具使用?
Is it possible to make this generic? That is, to pass which member function to call to apply
, and therefore have it as a generic utility?
我认为也许我可以使用 std::mem_fn
进行包装一个函数(std::mem_fn(&Foo::get)
)并将结果对象传递给apply
,但这不起作用,因为Foo
是一个类模板:
I thought perhaps I could use std::mem_fn
to wrap a function (std::mem_fn(&Foo::get)
) and pass the resulting object to apply
, but that don't work because Foo
is a class template:
有什么方法可以使这种泛型?
Is there any way to make this generic?
#include <iostream>
#include <tuple>
#include <utility>
template<size_t...>
struct Seq
{ };
template<size_t N, size_t... Sq>
struct GenSeq : GenSeq<N - 1, N - 1, Sq...>
{ };
template<size_t... Sq>
struct GenSeq<0, Sq...>
{
using type = Seq<Sq...>;
};
/////////////////////////////////////
struct Invoker
{
template<typename Func, typename Tuple, size_t... Sq>
static auto invoke(Func func, const Tuple& tuple, Seq<Sq...>)
-> decltype(func(std::get<Sq>(tuple).get()...))
{
// calls the .get() member on each object in the tuple
// I would like to make this generic
return func(std::get<Sq>(tuple).get()...);
}
template<typename Func, typename... Args>
static auto apply(Func func, const std::tuple<Args...>& args)
-> decltype(invoke(func, args, typename GenSeq<sizeof...(Args)>::type()))
{
return invoke(func, args, typename GenSeq<sizeof...(Args)>::type());
}
};
template<typename Func, typename Tuple>
inline auto apply(Func func, const Tuple& tuple)
-> decltype(Invoker::apply(func, tuple))
{
return Invoker::apply(func, tuple);
}
///////////////////////////////////////
template<typename T>
struct Foo
{
T i;
auto get() const -> decltype(i) { return i; }
};
template<typename... Ts>
struct Bar
{
Bar(Ts... ts) : tuple(std::make_tuple(Foo<Ts> { ts }...)) {}
std::tuple<Foo<Ts>...> tuple;
};
void func(int i, double d, char c)
{
std::cout << i << ", " << d << ", " << c << std::endl;
}
int main()
{
Bar<int, double, char> bar { 4, 1.23, 'a' };
apply(func, bar.tuple);
}
推荐答案
您不能使用mem_fn
创建一个包装来调用异构类型对象上的成员函数的包装器,因为mem_fn
创建的包装器会包装一个指向特定类型的特定成员的指针.
You can't use mem_fn
to create a wrapper that calls a member function on objects of heterogeneous type, as the wrapper created by mem_fn
wraps a pointer to a particular member of a particular type.
诀窍是使用可接受任何适当类型并调用成员函数的模板化函数调用运算符传递某些内容.
The trick is to pass something with a templated function call operator that can accept any appropriate type and call the member function.
在C ++ 14中,传递多态lambda:
In C++14, pass a polymorphic lambda:
[](auto&& obj) -> decltype(auto) { return std::forward<decltype(obj)>(obj).get(); }
对于C ++ 11,您需要手工编写等效的仿函数:
For C++11, you'd need to write the equivalent functor by hand:
struct call_get {
template<class T>
auto operator()(T&& obj) const -> decltype(std::forward<T>(obj).get()) {
return std::forward<T>(obj).get();
}
};
这篇关于通常在元组的每个元素上调用成员函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!