Search code examples
c++templatessequenceexpansionvariable-templates

How do I expand integer_sequence?


I have a function which looks like this:

template <typename T, std::size_t... I>
std::ostream& vector_insert(std::ostream& lhs, const char* delim, const T& rhs, std::index_sequence<I...>) {
    std::ostream_iterator<float> it(lhs, delim);

    ((*it++ = at(rhs, I)), ...);
    return lhs;
}

This is my final attempt and I'm still failing on my expansion of the integer_sequence I'm hoping someone can tell me how to write a line that will effectively expand to:

*it++ = at(rhs, 0U), *it++ = at(rhs, 1U), *it++ = at(rhs, 2U)

Other things I've tried are:

  1. *it++ = at(rhs, I...)
  2. *it++ = at(rhs, I)...
  3. (*it++ = at(rhs, I))...

All of them are giving me the error:

error C3520: I: parameter pack must be expanded in this context

How do I expand this thing?

EDIT:

@AndyG has pointed out that this seems to be a bug.


Solution

  • This seems like a compiler bug with Visual C++. I'm not aware of any easy fix for it other than simplifying the expression in which the parameter pack is expanded. Converting to a recursive approach seems to reliably work around the problem. For example :

    #include <array>
    #include <iostream>
    #include <iterator>
    
    template <typename T>
    const auto& at(const T& v, size_t i) { return v[i]; }
    
    // End of recursion
    template<class T>
    void vector_insert_impl(std::ostream_iterator<int> &, const char*, const T&)
    {}
    
    // Recursion case
    template<class T, std::size_t N, std::size_t... I>
    void vector_insert_impl(std::ostream_iterator<int> & iter, const char* delim, const T&rhs)
    {
        *iter++ = at(rhs, N);
    
        // Continue the recursion
        vector_insert_impl<T, I...>(iter, delim, rhs);
    }
    
    template <typename T, std::size_t... I>
    std::ostream& vector_insert(std::ostream& lhs, const char* delim, const T& rhs, std::index_sequence<I...>) 
    {
        std::ostream_iterator<int> it(lhs, delim);
    
        // Call the recursive implementation instead
        vector_insert_impl<T, I...>(it, delim, rhs);
    
        return lhs;
    }
    
    int main() {
        std::array<int, 5> v = { 1, 2, 3, 4, 5 };
        vector_insert(std::cout, " ", v, std::make_index_sequence<v.size()>());
    }
    

    Here, the parameter pack I is only expanded in the context of providing template parameters which VC++ has no trouble with.