Boost logo

Boost :

Subject: [boost] Variadics bug in MSVC-12.0
From: Gennadiy Rozental (rogeeff_at_[hidden])
Date: 2015-09-29 13:24:57


Hi,

While working on improving of implementation of data driven tests, I found
rather annoying bug in MSVC-12.0 with variadic templates. The code seems
to work fine with msvc-14.0, gcc 4.8 and clang 3.4. I did not try msvc-
13.0. Does anyone know a workaround? Example follows (try to comment
on/off line: auto const& t3).

Gennadiy

// C++ 14 index_sequence
template <std::size_t... Ns>
struct index_sequence {};

template<typename IS1, typename IS2>
struct merge_index_sequence;

template <std::size_t... Ns1, std::size_t... Ns2>
struct merge_index_sequence<index_sequence<Ns1...>,
index_sequence<Ns2...>> {
    typedef index_sequence<Ns1..., Ns2...> type;
};

template <std::size_t B, std::size_t E, typename Enabler = void>
struct make_index_sequence {
    typedef typename merge_index_sequence<
        typename make_index_sequence<B, (B + E)/2>::type,
        typename make_index_sequence<(B + E)/2, E>::type>::type type;
};

template <std::size_t B, std::size_t E>
struct make_index_sequence<B, E,
  typename std::enable_if<E == B + 1, void>::type> {
    typedef index_sequence<B> type;
};

template <typename... T>
using index_sequence_for =
   typename make_index_sequence<0, sizeof...(T)>::type;

//////////////////////////////////////////////////////////////////////////

template<typename T1, typename T2>
struct merged_tuple {
    typedef std::tuple<T1,T2> type;
    typedef std::tuple<T1 const&,T2 const&> ref;
};

template<typename T1, typename ...T>
struct merged_tuple<T1, std::tuple<T...>> {
    typedef std::tuple<T1, T...> type;
    typedef std::tuple<T1 const&, T const&...> ref;
};

template<typename ...T, typename T1>
struct merged_tuple<std::tuple<T...>, T1> {
    typedef std::tuple<T..., T1> type;
    typedef std::tuple<T const&..., T1 const&> ref;
};

template<typename ...T1, typename ...T2>
struct merged_tuple<std::tuple<T1...>, std::tuple<T2...>> {
    typedef std::tuple<T1..., T2...> type;
    typedef std::tuple<T1 const&..., T2 const&...> ref;
};

template<typename ...T1,
         typename ...T2,
         std::size_t ...I1,
         std::size_t ...I2>
inline typename merged_tuple<std::tuple<T1...>, std::tuple<T2...>>::ref
tuple_merge_impl( std::tuple<T1 const&...> const& a1,
                  std::tuple<T2 const&...> const& a2,
                  index_sequence<I1...> const& ,
                  index_sequence<I2...> const& )
{
    using ref_type = typename merged_tuple<std::tuple<T1...>,
                                           std::tuple<T2...>>::ref;

    return ref_type( std::get<I1>(a1)..., std::get<I2>(a2)... );
}

template<typename ...T1, typename ...T2>
inline typename merged_tuple<std::tuple<T1...>, std::tuple<T2...>>::ref
tuple_merge_impl( std::tuple<T1 const&...> const& a1,
                  std::tuple<T2 const&...> const& a2 )
{
    return tuple_merge_impl( a1, a2,
      index_sequence_for<T1...>{},
      index_sequence_for<T2...>{} );
}

template<typename T>
inline std::tuple<T const&>
as_tuple( T const& arg )
{
    return std::tuple<T const&>( arg );
}

template<typename ...T>
inline std::tuple<T...> const&
as_tuple( std::tuple<T...> const& arg )
{
    return arg;
}

template<typename T1, typename T2>
inline typename merged_tuple<T1, T2>::ref
tuple_merge( T1 const& a1, T2 const& a2 )
{
    return tuple_merge_impl( as_tuple( a1 ), as_tuple( a2 ) );
}

int main()
{
    auto const& t1 = tuple_merge( 1, 2 );
    auto const& t2 = tuple_merge( 3, 4 );

    auto const& t3 = tuple_merge( t1, 5 );
    auto const& t4 = tuple_merge( 6, t2 );

    return 0;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk