Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using initializer_list in template function

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?

like image 275
Edmund Avatar asked Mar 22 '23 06:03

Edmund


1 Answers

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);
}
like image 107
aschepler Avatar answered Apr 06 '23 08:04

aschepler