Workaround for lack of expression SFINAE

好久不见. 提交于 2019-12-13 00:43:02

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!