在元组的每个元素上一般调用成员函数
Generically call member function on each element of a tuple
第一步:扩展元组并将元素传递给函数:
我有一个函数需要 N 个参数
void func(int, double, char);
和一个具有匹配类型的元组
std::tuple<int, double, char> tuple;
As per this Whosebug question,我可以扩展元组并调用函数。
第二步:扩展一个元组并将对每个元素调用成员函数的结果传递给一个函数:
更进一步,我的元组包含 class 模板的多个实例:
template<typename T>
struct Foo;
std::tuple<Foo<int>, Foo<double>, Foo<char>>
Foo
有一个成员函数,Foo<T>::get()
其中 returns 一个 T
.
类型的值
As per this Whosebug answer,
我有下面的工作代码,它扩展元组并在每个元素上调用 element.get()
,最终将结果传递给 func
。
不幸的是,我已经硬编码了对element.get()
的调用。
第三步:对每个元组元素调用哪个成员函数进行通用规范:
(这是我正在寻求帮助的)
是否可以将其通用化?也就是说,将 which 成员函数传递给 apply
,从而将其作为通用实用程序?
我想也许我可以使用 std::mem_fn
包装一个函数 (std::mem_fn(&Foo::get)
) 并将生成的对象传递给 apply
,但这不起作用,因为 Foo
是一个 class 模板:
error: ‘template<class T> struct Foo’ used without template parameters
有什么方法可以使它通用吗?
下面的工作示例:
#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
创建的包装器包装了一个指向特定对象的特定成员的指针类型。
诀窍是使用模板化函数调用运算符传递一些东西,它可以接受任何适当的类型并调用成员函数。
在 C++14 中,传递多态 lambda:
[](auto&& obj) -> decltype(auto) { return std::forward<decltype(obj)>(obj).get(); }
对于 C++11,您需要手动编写等效的仿函数:
struct call_get {
template<class T>
auto operator()(T&& obj) const -> decltype(std::forward<T>(obj).get()) {
return std::forward<T>(obj).get();
}
};
第一步:扩展元组并将元素传递给函数:
我有一个函数需要 N 个参数
void func(int, double, char);
和一个具有匹配类型的元组
std::tuple<int, double, char> tuple;
As per this Whosebug question,我可以扩展元组并调用函数。
第二步:扩展一个元组并将对每个元素调用成员函数的结果传递给一个函数:
更进一步,我的元组包含 class 模板的多个实例:
template<typename T>
struct Foo;
std::tuple<Foo<int>, Foo<double>, Foo<char>>
Foo
有一个成员函数,Foo<T>::get()
其中 returns 一个 T
.
As per this Whosebug answer,
我有下面的工作代码,它扩展元组并在每个元素上调用 element.get()
,最终将结果传递给 func
。
不幸的是,我已经硬编码了对element.get()
的调用。
第三步:对每个元组元素调用哪个成员函数进行通用规范:
(这是我正在寻求帮助的)
是否可以将其通用化?也就是说,将 which 成员函数传递给 apply
,从而将其作为通用实用程序?
我想也许我可以使用 std::mem_fn
包装一个函数 (std::mem_fn(&Foo::get)
) 并将生成的对象传递给 apply
,但这不起作用,因为 Foo
是一个 class 模板:
error: ‘template<class T> struct Foo’ used without template parameters
有什么方法可以使它通用吗?
下面的工作示例:
#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
创建的包装器包装了一个指向特定对象的特定成员的指针类型。
诀窍是使用模板化函数调用运算符传递一些东西,它可以接受任何适当的类型并调用成员函数。
在 C++14 中,传递多态 lambda:
[](auto&& obj) -> decltype(auto) { return std::forward<decltype(obj)>(obj).get(); }
对于 C++11,您需要手动编写等效的仿函数:
struct call_get {
template<class T>
auto operator()(T&& obj) const -> decltype(std::forward<T>(obj).get()) {
return std::forward<T>(obj).get();
}
};