问题
If I have this tuple type:
std::tuple<int, string, std::tuple<...>, int>
How can I traverse it? I've been able to write functions that traverse a flat tuple, but not with nested tuples.
The problem seems to be for any implementation of a templated function or type that handles all the conceivable types in a nested tuple, there must be this case:
template<typename T>
void somefunc(T t)
{
// Do something to t
}
Which ends up being the best choice for overload resolution for every type, and you can't recursively traverse the tuple because you lose the information that it's a tuple. If you try to write a class or function that tries to determine whether it's a tuple or not, you still run in to the "false" case which has the same problem as above in that it ends up matching for every type and the tuple specialized version gets overlooked.
Is there a way I'm not aware of to check whether something is a tuple?
回答1:
Simply overload the someFunc()
function for tuples and non-tuple types:
template<typename... Ts>
void someFunc( const std::tuple<Ts...>& tuple )
{
/* traverse the elements of the tuple */
traverse_tuple( tuple );
}
template<typename T>
void someFunc( const T& value )
{
/* do something with the value */
}
Where traverse_tuple
is the same function you have implemented to traverse non-nested (flat) tuples. It calls someFunc()
for each member of the tuple.
For an implementation of a tuple traversing function, you could check this answer.
回答2:
If you want to check whether or not a type T
is a tuple, this should work:
#include <type_traits>
#include <tuple>
template<typename> struct is_tuple : std::false_type {};
template<typename... Ts> struct is_tuple<std::tuple<Ts...>> : std::true_type {};
static_assert( is_tuple<std::tuple<int>>::value, "Oops" );
static_assert( !is_tuple<int>::value, "Oops" );
int main() {}
回答3:
You may specialize struct/class instead of specializing function: adapt the following to your case (http://ideone.com/VgIJfj) :
namespace details
{
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(const std::tuple<Tp...> &, FuncT)
{ }
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(const std::tuple<Tp...>& t, FuncT f)
{
f(std::get<I>(t));
for_each<I + 1, FuncT, Tp...>(t, f);
}
template <typename T>
struct traverseType
{
void operator () (const T& t) const
{
std::cout << "it is a generic T:" << t << std::endl;
}
};
template <>
struct traverseType<int>
{
void operator () (int i) const
{
std::cout << "it is a int:" << i << std::endl;
}
};
// needed by the for_each.
struct traverseTypeCaller
{
template <typename T>
void operator () (const T& t) const
{
details::traverseType<T>()(t);
}
};
template <typename ...T>
struct traverseType<std::tuple<T...>>
{
void operator () (const std::tuple<T...>& t) const
{
std::cout << "it is a tuple:" << std::endl;
for_each(t, traverseTypeCaller());
}
};
}
template <typename T>
void traverseType(const T& t)
{
details::traverseTypeCaller()(t);
}
来源:https://stackoverflow.com/questions/19605944/traversing-nested-c11-tuple