[英]Initializer-list-constructing a vector of noncopyable (but movable) objects
可以將不可復制但可移動類型的push_back
rvalues轉換為該類型的向量:
#include <vector>
struct S
{
S(int);
S(S&&);
};
int main()
{
std::vector<S> v;
v.push_back(S(1));
v.push_back(S(2));
v.push_back(S(3));
}
但是,當我嘗試初始化列表構造具有相同rvalues的向量時,我得到關於所需的復制構造函數的錯誤:
#include <vector>
struct S
{
S(int);
S(S&&);
};
int main()
{
std::vector<S> v = {S(1), S(2), S(3)};
}
我在GCC 4.7中遇到以下錯誤:
In file included from include/c++/4.7.0/vector:63:0,
from test.cpp:1:
include/c++/4.7.0/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = S, _Args = {const S&}]':
include/c++/4.7.0/bits/stl_uninitialized.h:77:3: required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const S*, _ForwardIterator = S*, bool _TrivialValueTypes = false]'
include/c++/4.7.0/bits/stl_uninitialized.h:119:41: required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const S*, _ForwardIterator = S*]'
include/c++/4.7.0/bits/stl_uninitialized.h:260:63: required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = const S*, _ForwardIterator = S*, _Tp = S]'
include/c++/4.7.0/bits/stl_vector.h:1185:4: required from 'void std::vector<_Tp, _Alloc>::_M_range_initialize(_ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const S*, _Tp = S, _Alloc = std::allocator<S>]'
include/c++/4.7.0/bits/stl_vector.h:362:2: required from 'std::vector<_Tp, _Alloc>::vector(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = S, _Alloc = std::allocator<S>, std::vector<_Tp, _Alloc>::allocator_type = std::allocator<S>]'
test.cpp:11:41: required from here
include/c++/4.7.0/bits/stl_construct.h:77:7: error: no matching function for call to 'S::S(const S&)'
include/c++/4.7.0/bits/stl_construct.h:77:7: note: candidates are:
test.cpp:6:5: note: S::S(S&&)
test.cpp:6:5: note: no known conversion for argument 1 from 'const S' to 'S&&'
test.cpp:5:5: note: S::S(int)
test.cpp:5:5: note: no known conversion for argument 1 from 'const S' to 'int'
這應該允許嗎? 我認為它沒有任何技術障礙,但我現在還沒有標准方便......
也許8.5.4.5中的這一條款解釋了它(我的重點):
類型為std :: initializer_list的對象是從初始化列表構造的,就好像實現分配了一個N類型為E的元素的數組,其中N是初始化列表中的元素數。 使用初始化列表的相應元素對該數組的每個元素進行復制初始化 ,並構造std :: initializer_list對象以引用該數組。
因此,如果對象是可復制的,則只能從列表初始化。
更新:正如約翰內斯指出的那樣,復制初始化可以通過復制和移動構造函數來實現,因此僅靠這一點並不足以回答這個問題。 但是,這是18.9中描述的initializer_list
類規范的摘錄:
template<class _E>
class initializer_list
{
public:
typedef _E value_type;
typedef const _E& reference;
typedef const _E& const_reference;
typedef size_t size_type;
typedef const _E* iterator;
typedef const _E* const_iterator;
注意沒有非常量的typedef!
我剛剛嘗試制作一個IL構造函數,它將通過std::make_move_iterator
遍歷初始化列表,但由於const T &
無法轉換為T&&
,因此失敗了。
所以答案是:你不能離開IL,因為標准是這樣說的。
它似乎可能是編譯器問題。 這適用於g ++ 4.5.1 ( 點擊IdeOne在線演示)
結論 :從某種意義上說,舊的g ++實現沒有正確地標記錯誤; 初始化列表不支持移動它們的元素(元素在過程中被隱含地復制)。 感謝Kerrek SB 引用標准中的有用短語 。
舊程序(為了理解評論:)
編輯發現至少g ++ 4.6.1+似乎對此代碼抱有抱怨。
編輯在讀取std::initializer_list<T>
的源代碼后,我開始覺得庫不支持這種情況(看起來有意)。 標准是否實際上允許初始化列表轉發它的元素的xvalue-ness ...如果它們停在那里我不會感到驚訝(C ++ 0x中我仍然不支持完美轉發,而不是全部初始化參數需要具有相同(可扣除)類型。
在腰帶以下有更多標准的人可以幫忙嗎? http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2640.pdf
#include <vector>
struct S
{
S(int) {};
S(S&&) {};
};
int main()
{
std::vector<S> v = {S(1), S(2), S(3)};
std::vector<S> w = {std::move(S(1)), std::move(S(2)), std::move(S(3))};
std::vector<S> or_even_just = {1, 2, 3};
}
initializer_list僅提供const引用和const迭代器。 矢量無法從中移動。
template<class E>
class initializer_list {
public:
typedef E value_type;
typedef const E& reference;
typedef const E& const_reference;
typedef size_t size_type;
typedef const E* iterator;
typedef const E* const_iterator;
似乎答案是否為Kerrek SB的答案 。 但是您可以使用可變參數模板通過小輔助函數實現類似的功能:
#include <vector>
#include <utility>
template <typename T>
void add_to_vector(std::vector<T>* vec) {}
template <typename T, typename... Args>
void add_to_vector(std::vector<T>* vec, T&& car, Args&&... cdr) {
vec->push_back(std::forward<T>(car));
add_to_vector(vec, std::forward<Args>(cdr)...);
}
template <typename T, typename... Args>
std::vector<T> make_vector(Args&&... args) {
std::vector<T> result;
add_to_vector(&result, std::forward<Args>(args)...);
return result;
}
struct S {
S(int) {}
S(S&&) {}
};
int main() {
std::vector<S> v = make_vector<S>(S(1), S(2), S(3));
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.