list.begin()
タイプ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を読むと、すべての場合に関連する完全式には初期化子リストの使用が含まれているように見えるので、右辺値参照がぶら下がる危険はないと思います。