问题
I'm trying to call a function for each value in a std::tuple
, of course there is no way to iterate a tuple and so I've resorted to using the template techniques discussed in iterate over tuple
However, I'm using Visual Studio 2013 and it does not support expression SFINAE, so that code won't work. I've tried to partially specialize the templates based on a constant numbers (e.g 5, 4, 3, 2, 1, 0), but haven't had any success. I'm certainly no template expert, and so I was hoping somebody could help me out. My expression SFINAE code is below.
#include <iostream>
#include <tuple>
using namespace std;
struct ArgPush {
void push(bool x) {}
void push(int x) {}
void push(double x) {}
void push(const char* x) {}
void push(const std::string& x) {}
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
push_tuple(const std::tuple<Tp...>& t)
{ }
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
push_tuple(const std::tuple<Tp...>& t)
{
push(std::get<I>(t));
push_tuple<I + 1, Tp...>(t);
}
};
int main() {
ArgPush().push_tuple(std::make_tuple(1,2,3,4));
ArgPush().push_tuple(std::make_tuple("hello", "msvc makes me sad", 4, true));
return 0;
}
回答1:
MSVC doesn't like the equality comparisons being made within the enable_if
. So move these out from there to a helper template. Then your code compiles on VS2013.
template<std::size_t I, typename... Tp>
struct comparator
{
static const bool value = (I < sizeof...(Tp));
};
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<!comparator<I, Tp...>::value>::type
push_tuple(const std::tuple<Tp...>& t)
{ }
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<comparator<I, Tp...>::value>::type
push_tuple(const std::tuple<Tp...>& t)
{
push(std::get<I>(t));
push_tuple<I + 1, Tp...>(t);
}
回答2:
You can partial specialization instead of SFINAE:
template <std::size_t N>
struct helper
{
template <typename T>
static void push(T&& v)
{
// do something
}
template <typename ...Types>
static void push_tuple(const std::tuple<Types...>& t)
{
push(std::get<sizeof...(Types) - N>(t));
helper<N - 1>::push_tuple(t);
}
};
template <>
struct helper<0>
{
template <typename ...Types>
static void push_tuple(const std::tuple<Types...>&)
{
// nothing (end of iteration)
}
};
template <typename ...Types>
void push_tuple(const std::tuple<Types...>& t)
{
helper<sizeof...(Types)>::push_tuple(t);
}
来源:https://stackoverflow.com/questions/24097911/workaround-for-lack-of-expression-sfinae