0

With the a function taking std::initializer_list as argument like shown below

int sumOf(std::initializer_list<int> numbers) {
    int sum = 0;  
    for (auto x : numbers) {
        sum += x;
    }
    return sum;
}

This code works

auto sum = sumOf({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });

but not this

 int i[]  = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 auto x = sumOf(i);

Why does the second form not work? Or am I doing something wrong?

Edit:
From the gcc 4.7.2 implementation of std::intializer_list, the constructor of intializer_list is private and compiler needs to pass the size of the array.

  // The compiler can call a private constructor.
  constexpr initializer_list(const_iterator __a, size_type __l)
  : _M_array(__a), _M_len(__l) { }

I guess the compiler cannot judge the size of the array from the variable "i" in certain cases. If so, passing static array to intializer_list cannot be supported by the compiler (?).

4
  • But { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } really created a std::initializer_list. Commented Dec 6, 2012 at 7:22
  • 1
    Well, one passes an initializer list, as excepted by the function, and the other passes and array, what else should happen. An initializer list is not just an array. What about changing it to auto i = { ... };, not sure if this works, though. Commented Dec 6, 2012 at 8:20
  • @ChristianRau - it works with auto i = { ... }; but "i" seems to be no more behaving as an int array. Commented Dec 6, 2012 at 13:04
  • @KiranMohan No, because now it is a std::initializer_list, which is the type expected by the function, and which is totally different from an array. Commented Dec 6, 2012 at 15:17

2 Answers 2

3

i is not an initializer_list. initializer_list is not some shorthand for "static array". It's a special object that can only be created (outside of copy-construction) by using a braced-init-list (ie: {...} syntax).

When you do int i[] = {...}; you are performing aggregate initialization on an array. i is an array of ints, not an initializer_list.

What you want is a template function, which can take anything you can use range-based-for over:

template<typename Rng>
int sumOf(const Rng &numberRange) {
    int sum = 0;  
    for (auto x : numberRange) {
        sum += x;
    }
    return sum;
}
Sign up to request clarification or add additional context in comments.

2 Comments

the template version does not work when directly passing values with the {...} syntax unless you have specialized version of sumOf() which takes std::initializer_list
@KiranMohan: Currently, that's correct and the only discrepancy between auto and normal template argument deduction. There's a proposal to have that fixed in C++Next, though.
1

You can do the index tuple trick, as used by many people before

template<int N, int ...X>
struct I : struct I<N-1, N, X...> {};

template<int X...>
struct I<0, X...> {
  typedef I type;
};

template<typename F, typename T, int N, int ...X>
decltype(f(std::declval<std::initializer_list<T>>()))
make_list(T const (&a)[N], F f, I<X...>) 
{
   return f(std::initializer_list<T>{a[X]...});
}

template<typename F, typename T, int N>
decltype(f(std::declval<std::initializer_list<T>>()))
make_list(T const(&a)[N], F f) {
   return make_list(a, f, typename I<N-1>::type());
}

Usage is easy

make_list(i, &sumOf);

Or using a lambda

make_list(i, [](std::initializer_list<int> x) {
  return sumOf(x);
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.