1

taking the answer from here : iterate over tuple regarding printing std::tuple components, here is the code :

template<std::size_t I = 0, typename... Tp>
 typename std::enable_if<I == sizeof...(Tp), void>::type
print(const std::tuple<Tp...>& t)
{ }

template<std::size_t I = 0, typename... Tp>
 typename std::enable_if<I < sizeof...(Tp), void>::type
    print(const std::tuple<Tp...>& t)
{
    std::cout << std::get<I>(t) << std::endl;
    print <i, Tp...> (t);
}

this compiles and works perfectly on GCC, but fails to compile on VC++ (I use visual studio 2013). the error I'm gettting :

Error   4   error C2893: Failed to specialize function template 'std::enable_if<I==1,void>::type print(const std::tuple<_Types1...> &)' 
Error   3   error C2770: invalid explicit template argument(s) for 'std::enable_if<I<1,void>::type print(const std::tuple<_Types1...> &)'   

appearntly there is a documented bug on C2770 when using std::enable_if with explicit template-arguments. some developers recommended using const int as pre-argument for the template as

const int i = I+1;
print<i,Tp...>(t);

but this does not work either. there were other solutions also such as use some macros , but they fail too.
does someone have a work around it ? I searched for a solution but found none that actually works.
thanks.

Community
  • 1
  • 1
David Haim
  • 25,446
  • 3
  • 44
  • 78

2 Answers2

1

You may use one of the following:

  • using decrementing recursion and (partial) specialization:

    namespace detail
    {
        template <std::size_t N>
        struct printer
        {
            template <typename TUPLE>
            void operator () (const TUPLE& t) const
            {
                printer<N - 1>{}(t);
                std::cout << std::get<N - 1>(t) << std::endl;
            }
        };
    
        template <>
        struct printer<0>
        {
            template <typename TUPLE>
            void operator () (const TUPLE& t) const {}
        };
    
    }
    
    
    template <typename ... Ts>
    void print(const std::tuple<Ts...>& t)
    {
        detail::printer<sizeof...(Ts)>{}(t);
    }
    
  • or using index_sequence

    #if 1 // Not in C++11
    #include <cstdint>
    
    template <std::size_t...> struct index_sequence {};
    
    template <std::size_t N, std::size_t... Is>
    struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};
    
    template <std::size_t... Is>
    struct make_index_sequence<0u, Is...> : index_sequence<Is...>{};
    
    #endif
    
    namespace detail
    {
    
        template <std::size_t... Is, typename TUPLE>
        void print(const TUPLE& t, index_sequence<Is...>)
        {
            int dummy[] = {0, ((std::cout << std::get<Is>(t) << std::endl), 0)...};
            (void) dummy; // To remove warning about unused variable.
        }
    
    }
    
    template <typename ... Ts>
    void print(const std::tuple<Ts...>& t)
    {
        detail::print(t, make_index_sequence<sizeof...(Ts)> {});
    }
    
Jarod42
  • 203,559
  • 14
  • 181
  • 302
1

To retain the structure of the original code given in the question, the following workaround works for me in MSVC 2013:

Define the following helper:

// workaround for msvc `sizeof...(Tp)` not working
template<typename... Tp>
struct sizeof_pack___ { static const std::size_t value = sizeof...(Tp); };

Then replace the two occurrences of sizeof...(Tp) with sizeof_pack___<Tp...>::value.

The final code would look like this:

template<std::size_t I = 0, typename... Tp>
 typename std::enable_if<I == sizeof_pack___<Tp...>::value, void>::type
    print(const std::tuple<Tp...>& t)
{ }

template<std::size_t I = 0, typename... Tp>
 typename std::enable_if<I < sizeof_pack___<Tp...>::value, void>::type
    print(const std::tuple<Tp...>& t)
{
    std::cout << std::get<I>(t) << std::endl;
    print <i, Tp...> (t);
}
Ross Bencina
  • 3,822
  • 1
  • 19
  • 33