list.begin()
type const T *
があり、定数オブジェクトから移動する方法がないため、これは前述のように機能しません。言語設計者はおそらく、イニシャライザリストにたとえば文字列定数を含めることができるようにするために、そこから移動するのは不適切だと考えています。
ただし、初期化リストに右辺値式が含まれていることがわかっている場合(またはユーザーにそれらを強制的に記述したい場合)、それを機能させるトリックがあります(私はSumantの答えに触発されましたこれですが、解決策はそれよりもはるかに簡単です。初期化リストに格納されている要素は、T
値ではなく、をカプセル化する値である必要がありますT&&
。これらの値自体がconst
修飾されている場合でも、変更可能な右辺値を取得できます。
template<typename T>
class rref_capture
{
T* ptr;
public:
rref_capture(T&& x) : ptr(&x) {}
operator T&& () const { return std::move(*ptr); } // restitute rvalue ref
};
ここで、initializer_list<T>
引数を宣言する代わりに、引数を宣言しinitializer_list<rref_capture<T> >
ます。以下は、std::unique_ptr<int>
移動セマンティクスのみが定義されているスマートポインターのベクトルを含む具体的な例です(したがって、これらのオブジェクト自体を初期化リストに格納することはできません)。しかし、以下のイニシャライザリストは問題なくコンパイルされます。
#include <memory>
#include <initializer_list>
class uptr_vec
{
typedef std::unique_ptr<int> uptr; // move only type
std::vector<uptr> data;
public:
uptr_vec(uptr_vec&& v) : data(std::move(v.data)) {}
uptr_vec(std::initializer_list<rref_capture<uptr> > l)
: data(l.begin(),l.end())
{}
uptr_vec& operator=(const uptr_vec&) = delete;
int operator[] (size_t index) const { return *data[index]; }
};
int main()
{
std::unique_ptr<int> a(new int(3)), b(new int(1)),c(new int(4));
uptr_vec v { std::move(a), std::move(b), std::move(c) };
std::cout << v[0] << "," << v[1] << "," << v[2] << std::endl;
}
1つの質問には答えが必要です。イニシャライザリストの要素が真のprvaluesである必要がある場合(例ではxvalues)、言語は対応する一時オブジェクトのライフタイムがそれらが使用されるポイントまで延長されることを保証しますか?率直に言って、規格の関連セクション8.5がこの問題にまったく対処していないと思います。ただし、1.9:10を読むと、すべての場合に関連する全式がイニシャライザリストの使用を包含しているように見えるため、右辺値参照をぶら下げる危険はないと思います。
initializer_list<T>
が非 const であることを定義しています。同様に、オブジェクトをinitializer_list<int>
指しint
ます。しかし、それは欠点だと思います-コンパイラが静的にリストを読み取り専用メモリに割り当てることができることが意図されています。