我需要为任意元组中的每个元素调用-模板或重载-函数。确切地说,我需要在元组中指定的元素上调用此函数。

例如。我有一个元组std::tuple<int, float> t{1, 2.0f};和一个功能

class Lambda{
public:
   template<class T>
   void operator()(T arg){ std::cout << arg << "; "; }
};

我需要一些struct/function Apply,如果像Apply<Lambda, int, float>()(Lambda(), t)这样调用它将产生:
1; 2.0f;

而不是2.0f; 1;

请注意,如果将“原始”参数包传递给函数,并且知道如何以相反的顺序对元组执行此操作,则我知道解决方案。但是,以下对Apply进行部分特化的尝试失败了:
template<class Func, size_t index, class ...Components>
class ForwardsApplicator{
public:
    void operator()(Func func, const std::tuple<Components...>& t){
        func(std::get<index>(t));
        ForwardsApplicator<Func, index + 1, Components...>()(func, t);
    }
};

template<class Func, class... Components>
class ForwardsApplicator < Func, sizeof...(Components), Components... > {
public:
    void operator()(Func func, const std::tuple<Components...>& t){}
};

int main{
    ForwardsApplicator<Lambda, 0, int, float>()(Lambda{}, std::make_tuple(1, 2.0f));
}

代码已编译,但仅输出第一个参数。但是,如果我将ForwardsApplicator特化替换为
template<class Func, class... Components>
class ForwardsApplicator < Func, 2, Components... >{...}

它可以正常工作-但是,当然,仅适用于长度为2的元组。如何(如果可能的话,优雅地)如何处理任意长度的元组?

编辑:谢谢大家的回答!这三者实际上都是直截了当的,并从所有可能的角度解释问题。

最佳答案

问题是 size...(Components) 不能用于未知类型列表 Components 的特化。 GCC 提示这个错误:



我建议采用稍微不同的方法。首先,将类型列表 Components 移动到 operator() 的模板参数中,即:

template<class ...Components>
void operator()(Func func, const std::tuple<Components...>& t) {
    ...
}

然后,颠倒调用顺序:首先进行递归调用,然后使用 index-1 进行调用(即调用最后一个元组元素)。用 index = sizeof...(Components) 开始这个递归,直到 index = 0 是 noop (所以特化有 0 ,独立于 sizeof...(Components) ,这是我开始谈论的问题)。

为了帮助调用它,添加一个用于模板参数推导的函数:
// General case (recursion)
template<class Func, size_t index>
class ForwardsApplicator{
public:
    template<class ...Components>
    void operator()(Func func, const std::tuple<Components...>& t){
        ForwardsApplicator<Func, index - 1>()(func, t);
        func(std::get<index - 1>(t));
    }
};

// Special case (stop recursion)
template<class Func>
class ForwardsApplicator<Func, 0> {
public:
    template<class ...Components>
    void operator()(Func func, const std::tuple<Components...>& t){}
};

// Helper function for template type deduction
template<class Func, class ...Components>
void apply(Func func, const std::tuple<Components...>& t) {
    ForwardsApplicator<Func, sizeof...(Components)>()(func, t);
}

然后很容易调用,不需要调用站点上的任何模板参数:
apply(Lambda{}, std::make_tuple(1, 2.0f));

Live demo

关于c++ - 以自然(非反向)顺序将func应用于std::tuple中的元素,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28343591/

10-11 23:03
查看更多