이것은 list.begin()
유형이 있기 때문에 명시된대로 작동하지 않으며 const T *
상수 객체에서 이동할 수있는 방법이 없습니다. 언어 디자이너는 아마도 초기화 목록에 예를 들어 문자열 상수를 포함 할 수 있도록 그렇게 만들었을 것입니다.
그러나 이니셜 라이저 목록에 rvalue 표현식이 포함되어 있다는 것을 알고있는 경우 (또는 사용자가이를 작성하도록 강제하려는 경우) 작동하도록하는 트릭이 있습니다 (Sumant의 답변에서 영감을 얻었습니다. 그러나 해결책은 그보다 훨씬 간단합니다). 이니셜 라이저 목록에 저장된 요소는 T
값이 아니라을 캡슐화하는 값 이어야 합니다 T&&
. 그런 다음 해당 값 자체가 const
한정된 경우에도 수정 가능한 rvalue를 검색 할 수 있습니다.
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;
}
한 가지 질문에 답이 필요합니다. 이니셜 라이저 목록의 요소가 참 prvalue (예 : xvalue) 여야하는 경우 언어는 해당 임시의 수명이 사용되는 지점까지 확장되도록 보장합니까? 솔직히, 표준의 관련 섹션 8.5가이 문제를 전혀 다루지 않는다고 생각합니다. 그러나 1.9 : 10을 읽으면 모든 경우에 관련된 full-expression 이 이니셜 라이저 목록의 사용을 포함하는 것처럼 보이 므로 rvalue 참조를 매달릴 위험이 없다고 생각합니다.
initializer_list<T>
있는 비 -const. 마찬가지로 객체를initializer_list<int>
나타냅니다int
. 하지만 이것이 결함이라고 생각합니다. 컴파일러가 읽기 전용 메모리에 목록을 정적으로 할당 할 수 있다는 것입니다.