I have a function named _push which can handle different parameters, including tuples, and is supposed to return the number of pushed elements.
For example, _push(5) should push '5' on the stack (the stack of lua) and return 1 (because one value was pushed), while _push(std::make_tuple(5, "hello")) should push '5' and 'hello' and return 2.
I can't simply replace it by _push(5, "hello") because I sometimes use _push(foo()) and I want to allow foo() to return a tuple.
Anyway I can't manage to make it work with tuples:
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;
}
Let's say you want to push a tuple<int,bool>. This is how I expect it to work:
_push<{int,bool}, 2> is called (first definition)_push<{int,bool}, 1> is called (first definition)_push<{int,bool}, 0> is called (second definition)However with g++ 4.5 (the only compiler I have which supports variadic templates), I get an error concerning _push<Args...,N-1>(t) (line 3) saying that it couldn't find a matching function to call (without any further detail). I tried without the "..." but I get another error saying that the parameters pack is not expanded.
How can I fix this?
PS: I know that you can do this using a template struct (this is in fact what I was doing before), but I'd like to know how to do it with a function
PS 2: PS2 is solved, thanks GMan
I don't have a compiler to test any of this, so you'll have to report any issues.
The following should allow you to iterate across a tuple calling a function. It's based off your logic, with a few minor changes. (N is a std::size_t, it's the first parameter to allow Args (and Func) to be deduced on further calls, it just calls some function instead of performing a specific task). Nothing too drastic:
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;
}
Assuming that all works, you then just have:
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;
};
And lastly:
std::size_t pushCount = iterate(someTuple, push_lua_stack()).count;
Let me know if that all makes sense.
Since you seem to really be seriously against structs for some reason, just make a function like this:
template <typename T>
void push_lua(const T& pX)
{
// push pX onto lua stack
}
And change everything to specifically call that function:
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);
}
No idea why you'd avoid generic functionality though, or be so against structs.
Oh how nice polymorphic lambda's would be. Ditch the utility push_lua_stack class and just write:
std::size_t count = 0;
iterate(someTuple, [&](auto pX)
{
// push onto lua stack
++count;
});
Oh well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With