缺乏表达SFINAE的解决方法

时间:2014-06-07 13:50:25

标签: c++ c++11 sfinae

我正在尝试为std::tuple中的每个值调用一个函数,当然没有办法迭代元组,因此我使用iterate over tuple中讨论的模板技术

但是,我使用的是Visual Studio 2013,它不支持表达式SFINAE,因此代码不起作用。我试图基于常数(例如5,4,3,2,1,0)对模板进行部分专门化,但没有取得任何成功。我当然不是模板专家,所以我希望有人可以帮助我。我的表达式SFINAE代码如下。

#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;
}

2 个答案:

答案 0 :(得分:3)

MSVC不喜欢在enable_if内进行的等式比较。所以将它们从那里移到辅助模板上。然后你的代码在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);
}

答案 1 :(得分:2)

您可以部分专业化而不是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);
}