1

Straightforward using of default parameter value to generate integer sequence as follows lead to hard error (complier clang-3.6):

#include <iostream>
#include <utility>

#include <cstdlib>

template< std::size_t M, std::size_t N > // say M - arity, N - number of types
struct test
{

    template< std::size_t ...i >
    void
    operator () (std::index_sequence< i... > = std::make_index_sequence< M >{}) const
    {
        std::size_t indices[M];
        for (std::size_t & m : indices) {
            m = 0;
        }
        for (;;) {
            (std::cout << ... << indices[i]) << std::endl;
            std::size_t m = 0;
            for (;;) {
                std::size_t & n = indices[m];
                ++n;
                if (n != N) {
                    break;
                }        
                n = 0; 
                if (++m == M) {
                    return;
                }
            }
        }
    }

};

int
main()
{
#if 0
    test< 3, 3 >{}(); // hard error
#else
    test< 3, 3 >{}(std::make_index_sequence< 3 >{}); // ugly workaround
#endif
    return EXIT_SUCCESS;
}

It looks strange, because simple substitution works as intended.

Why is it so? Why default parameter cannot be assigned in above a case, but explicit assignment works?

Appending const & or && to parameter type does nothing.

Tomilov Anatoliy
  • 15,657
  • 10
  • 64
  • 169
  • @LightnessRacesinOrbit http://coliru.stacked-crooked.com/a/14a759868ea02e34 – Tomilov Anatoliy Jun 20 '15 at 16:09
  • Seems it expect exact equivalence of the types. `std::make_index_sequence< M >::operator std::index_sequence< i... > () const` would be very useful feature. – Tomilov Anatoliy Jun 20 '15 at 16:11
  • @LightnessRacesinOrbit Though using instance of `struct I { constexpr operator std::index_sequence< 0, 1, 2 > () const { return {}; } };` as default value does not make sense. http://coliru.stacked-crooked.com/a/6029f0ba22cde57b – Tomilov Anatoliy Jun 20 '15 at 16:39
  • 1
    You're calling `operator()()` with no arguments so `i...` is deduced to an empty pack. You now need to have a conversion from `index_sequence<0, ..., M-1>` to `index_sequence<>` which, unless `M` is 0, isn't possible. – David G Jun 20 '15 at 16:53
  • @0x499602D2 Interesting interpretation, but it is not evident from the *clang*s error description. Thanks. – Tomilov Anatoliy Jun 20 '15 at 16:56
  • _In the question...._ – Lightness Races in Orbit Jun 20 '15 at 17:32

1 Answers1

3

Template arguments can't be deduced from default arguments. This is why we typically delegate to a helper function before building the sequence:

void operator()() const {
    helper(std::make_index_sequence<M>{});
}

template<std::size_t... i>
void helper(std::index_sequence<i...>) const;
David G
  • 94,763
  • 41
  • 167
  • 253
  • What are the root causes of such a restriction? – Tomilov Anatoliy Jun 20 '15 at 15:45
  • @Orient The standard simply lists it as a non-deduced context. I was not aware of a rationale for it until I read this http://stackoverflow.com/a/9629112/701092 – David G Jun 20 '15 at 15:48
  • @Orient IMO a better way of explaining is that when creating the candidate set for overload resolution the compiler needs to perform template argument deduction. Default arguments can cause unexpected/unwanted behavior if template arguments can be deduced from them. – David G Jun 20 '15 at 16:30