一般对元组的每个元素调用成员函数

2024-03-04

第一步:展开元组并将元素传递给函数:

我有一个带有 N 个参数的函数

void func(int, double, char);

和一个具有匹配类型的元组

std::tuple<int, double, char> tuple;

根据这个 stackoverflow 问题 https://stackoverflow.com/questions/687490/how-do-i-expand-a-tuple-into-variadic-template-functions-arguments,我能够扩展元组并调用该函数。

第二步:展开一个元组并将对每个元素调用成员函数的结果传递给函数:

更进一步,我的元组包含类模板的多个实例:

template<typename T>
struct Foo;

std::tuple<Foo<int>, Foo<double>, Foo<char>>

Foo有一个成员函数,Foo<T>::get()它返回一个类型的值T.

根据这个 stackoverflow 答案 https://stackoverflow.com/a/7858971/955273, 我有下面的工作代码,它扩展元组并调用element.get()对每个元素,最终将结果传递给func.

不幸的是我已经硬编码的打电话给element.get().

第三步:使对每个元组元素调用哪个成员函数的规范变得通用:

(这就是我正在寻求帮助的事情)

是否可以使这个通用?也就是说,要通过which要调用的成员函数apply,因此将其作为通用实用程序?

我想也许我可以用std::mem_fn http://en.cppreference.com/w/cpp/utility/functional/mem_fn包装一个函数(std::mem_fn(&Foo::get)) 并将结果对象传递给apply,但这不起作用,因为Foo是一个类模板:

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(); 
    } 
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一般对元组的每个元素调用成员函数 的相关文章

随机推荐