C++ 0x:使用函数迭代元组

Tom*_*a17 3 c++ tuples c++11

我有一个名为的函数_push,它可以处理不同的参数,包括元组,并且应该返回推送元素的数量.

例如,_push(5)应该在堆栈上推送'5'(lua堆栈)并返回1(因为推送了一个值),同时_push(std::make_tuple(5, "hello"))应该按'5'和'hello'并返回2.

我不能简单地替换它_push(5, "hello")因为我有时使用_push(foo())并且我想允许foo()返回一个元组.

无论如何,我无法使它与元组一起工作:

template<typename... Args, int N = sizeof...(Args)>
int _push(const std::tuple<Args...>& t, typename std::enable_if<(N >= 1)>::type* = nullptr) {
 return _push<Args...,N-1>(t) + _push(std::get<N-1>(t));
}

template<typename... Args, int N = sizeof...(Args)>
int _push(const std::tuple<Args...>& t, typename std::enable_if<(N == 0)>::type* = nullptr) {
 return 0;
}
Run Code Online (Sandbox Code Playgroud)

假设你想推动一个tuple<int,bool>.这就是我期望它的工作方式:

  • _push<{int,bool}, 2> 被称为(第一个定义)
  • _push<{int,bool}, 1> 被称为(第一个定义)
  • _push<{int,bool}, 0> 被称为(第二个定义)

但是对于g ++ 4.5(我唯一支持可变参数模板的编译器),我得到一个错误_push<Args...,N-1>(t)(第3行),说它无法找到匹配的函数来调用(没有任何进一步的细节).我尝试没有"...",但我得到另一个错误,说参数包没有扩展.

我怎样才能解决这个问题?

PS:我知道你可以使用模板结构来实现这一点(这实际上就是我以前做过的事情),但我想知道如何用一个函数来做

PS 2:PS2解决了,感谢GMan

GMa*_*ckG 6

I don't have a compiler to test any of this, so you'll have to report any issues.

以下应该允许您遍历调用函数的元组.它基于你的逻辑,只有一些小的改变.(N是一个std::size_t,它是允许Args(和Func)在进一步调用中推导出的第一个参数,它只调用某个函数而不是执行特定任务).没什么太激烈的:

namespace detail
{
    // just to keep things concise and readable
    #define ENABLE_IF(x) typename std::enable_if<(x)>::type

    // recursive case
    template <std::size_t N, typename... Args, typename Func>
    ENABLE_IF(N >= 1) iterate(const std::tuple<Args...>& pTuple, Func& pFunc)
    {
        pFunc(std::get<N - 1>(pTuple));

        iterate<N - 1>(pTuple, pFunc);
    }

    // base case
    template <std::size_t N, typename... Args, typename Func>
    ENABLE_IF(N == 0) iterate(const std::tuple<Args...>&, Func&)
    {
        // done
    }
}

// iterate tuple
template <typename... Args, typename Func>
Func iterate(const std::tuple<Args...>& pTuple, Func pFunc)
{
    detail::iterate<sizeof...(Args)>(pTuple, pFunc);

    return pFunc;
}
Run Code Online (Sandbox Code Playgroud)

假设一切正常,那么你只需:

struct push_lua_stack
{
    // constructor taking reference to stack to push onto
    // initialize count to 0, etc....

    template <typename T>
    void operator()(const T& pX)
    {
        // push pX onto lua stack
        ++count;
    }

    std::size_t count;
};
Run Code Online (Sandbox Code Playgroud)

最后:

std::size_t pushCount = iterate(someTuple, push_lua_stack()).count;
Run Code Online (Sandbox Code Playgroud)

如果这一切都有意义,请告诉我.


由于某些原因你似乎真的非常反对结构,只需创建一个这样的函数:

template <typename T>
void push_lua(const T& pX)
{
    // push pX onto lua stack
}
Run Code Online (Sandbox Code Playgroud)

并改变一切专门调用该功能:

namespace detail
{
    // just to keep things concise and readable
    #define ENABLE_IF(x) std::enable_if<(x)>::type* = nullptr

    // recursive case
    template <std::size_t N, typename... Args>
    typename ENABLE_IF(N >= 1) iterate(const std::tuple<Args...>& pTuple)
    {
        // specific function instead of generic function
        push_lua(std::get<N - 1>(pTuple));

        iterate<N - 1>(pTuple);
    }

    // base case
    template <std::size_t N, typename... Args, typename Func>
    typename ENABLE_IF(N == 0) iterate(const std::tuple<Args...>&, Func&)
    {
        // done
    }
}

// iterate tuple
template <typename... Args>
void _push(const std::tuple<Args...>& pTuple)
{
    detail::iterate<sizeof...(Args)>(pTuple);
}
Run Code Online (Sandbox Code Playgroud)

不知道你为什么要避免泛型功能,或者反对结构.


哦多态lambda会有多好.抛弃实用程序push_lua_stack类,然后写:

std::size_t count = 0;

iterate(someTuple, [&](auto pX)
                    {
                        // push onto lua stack
                        ++count;
                    });
Run Code Online (Sandbox Code Playgroud)

那好吧.