4

関数テンプレートfooを使用して引数を に変換しようとしていinitializer_listます。ただし、initializer_list変換されたには、入力引数と同じではない奇妙な値があります。

#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.
}

ライブコード

出力は次のとおりです。

1,2,3
-326483696,32767,0

ここで何が問題なのですか?

4

1 に答える 1

7

std::initializer_list<T>一時配列を参照するため、一時オブジェクトまたは関数パラメーターとしてのみ使用する必要があります。

8.5.4/5-6:

type のオブジェクトは、実装が type のN要素のstd::initializer_list<E>一時配列を割り当てたかのように、初期化子リストから構築されます。ここで、Nは初期化子リスト内の要素の数です。...const E

配列の有効期間は他の一時オブジェクト (12.2) とinitializer_list同じですが、配列からオブジェクトを初期化すると、参照を一時オブジェクトにバインドするのとまったく同じように配列の有効期間が延長されます。

18.9/2:

type のオブジェクトは、 typeinitializer_list<E>のオブジェクトの配列へのアクセスを提供しますconst E。[注: ポインターのペアまたはポインターと長さは、initializer_list. initializer_list8.5.4 で指定されている初期化リストを実装するために使用されます。初期化子リストをコピーしても、基礎となる要素はコピーされません。]

したがって、initializer_listオブジェクトを返すことは次のように悪いことです。

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

int_ref func() {
    int n = 5;
    return int_ref(n);
}
于 2013-09-28T12:57:16.403 に答える