4

I am trying to use a function template foo to convert arguments to a initializer_list. However, the initializer_list it converted has strange values which are not the same as the input arguments.

#include <iostream>
#include <iterator>
#include <string>
#include <vector>

using namespace std;

template<class T>
void func(std::initializer_list<T> a_args)
{
    if (a_args.begin() != a_args.end())
    {
        auto last = prev(a_args.end());
        copy(a_args.begin(), last, ostream_iterator<int>(cout, ","));
        cout << *last;
    }
    cout << endl;
}

template<class T, class ...Args>
struct first_of
{
    typedef T type;
};

template<class ...Args>
initializer_list<typename first_of<Args...>::type> foo(Args&&... args)
{
    return { forward<Args>(args)... };
}

int main()
{
    func({1,2,3});
    auto x = foo(1,2,3);
    func(x); //this should be the same as func({1,2,3}) but not.
}

LIVE CODE

The ouput is as follows:

1,2,3
-326483696,32767,0

What is wrong here?

2
  • 1
    Initializer lists aren't meant to be held and used later. Commented Sep 28, 2013 at 12:33
  • Copying an initializer_list (such as when returning it from a function) does not copy the underlying elements. Commented Sep 28, 2013 at 12:53

1 Answer 1

8

std::initializer_list<T> should only be used as a temporary object or function parameter, since it refers to a temporary array.

8.5.4/5-6:

An object of type std::initializer_list<E> is constructed from an initializer list as if the implementation allocated a temporary array of N elements of type const E, where N is the number of elements in the initializer list. ...

The array has the same lifetime as any other temporary object (12.2), except that initializing an initializer_list object from the array extends the lifetime of the array exactly like binding a reference to a temporary.

18.9/2:

An object of type initializer_list<E> provides access to an array of objects of type const E. [Note: A pair of pointers or a pointer plus a length would be obvious representations for initializer_list. initializer_list is used to implement initializer lists as specified in 8.5.4. Copying an initializer list does not copy the underlying elements.]

So returning an initializer_list object is just as bad as:

struct int_ref {
    int& ref;
    explicit constexpr int_ref(int& r) : ref(r) {}
};

int_ref func() {
    int n = 5;
    return int_ref(n);
}
Sign up to request clarification or add additional context in comments.

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.