2012-01-09 3 views
45

다음 코드 GCC 컴파일시emplace_back()이 균일 한 초기화를 사용하지 않는 이유는 무엇입니까?

#include <vector> 

struct S 
{ 
    int x, y; 
}; 

int main() 
{ 
    std::vector<S> v; 
    v.emplace_back(0, 0); 
} 

다음 에러를 제공합니다

In file included from c++/4.7.0/i686-pc-linux-gnu/bits/c++allocator.h:34:0, 
       from c++/4.7.0/bits/allocator.h:48, 
       from c++/4.7.0/vector:62, 
       from test.cpp:1: 
c++/4.7.0/ext/new_allocator.h: In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = S; _Args = {int, int}; _Tp = S]': 
c++/4.7.0/bits/alloc_traits.h:265:4: required from 'static typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = S; _Args = {int, int}; _Alloc = std::allocator<S>; typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type = void]' 
c++/4.7.0/bits/alloc_traits.h:402:4: required from 'static void std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = S; _Args = {int, int}; _Alloc = std::allocator<S>]' 
c++/4.7.0/bits/vector.tcc:97:6: required from 'void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {int, int}; _Tp = S; _Alloc = std::allocator<S>]' 
test.cpp:11:24: required from here 
c++/4.7.0/ext/new_allocator.h:110:4: error: new initializer expression list treated as compound expression [-fpermissive] 
c++/4.7.0/ext/new_allocator.h:110:4: error: no matching function for call to 'S::S(int)' 
c++/4.7.0/ext/new_allocator.h:110:4: note: candidates are: 
test.cpp:3:8: note: S::S() 
test.cpp:3:8: note: candidate expects 0 arguments, 1 provided 
test.cpp:3:8: note: constexpr S::S(const S&) 
test.cpp:3:8: note: no known conversion for argument 1 from 'int' to 'const S&' 
test.cpp:3:8: note: constexpr S::S(S&&) 
test.cpp:3:8: note: no known conversion for argument 1 from 'int' to 'S&&' 

vectoremplace_back()의 인수의 요소를 구성하는 일반 () 생성자의 구문을 사용하는 것을 제안. 왜 vector은 위와 같은 예제를 만들기 위해 {} 균일 초기화 구문을 대신 사용하지 않습니까?

{} (하나가있을 때 생성자를 호출하지만 여전히 존재하지 않을 때 작동 함)을 사용하면 잃을 것이 아무것도없는 것처럼 보입니다. C++의 정신에 더 가까울 것입니다. 11 {}을 사용하십시오 - 어쨌든 균일화 초기화의 전체 점은 객체를 초기화하기 위해 균일하게, 즉 어디에서나 사용된다는 것입니다.

답변

42

위대한 마음은 비슷하다고 생각합니다. 나는 결함 보고서를 제출하고 바로이 주제에 대한 표준을 제안했다. Direct vs uniform initialization in std::allocator :

http://cplusplus.github.com/LWG/lwg-active.html#2089

또한, 루크 덴톤은 내가 어려움을 이해하고 도움을 주었다. EmplaceConstructible (23.2.1 [container.requirements.general]/13)가 요구 객체를 초기화하는 데 사용

는 직접 초기화가 발생한다. emplace로 std :: initializer_list 생성자를 사용하거나 을 초기화하려면 초기화 된 유형을 으로 명명하고 임시로 이동해야합니다. 이는 std :: allocator :: construct의 결과입니다. 목록 초기화 ("균일 초기화"라고도 함) 구문이 아닌 직접 초기화를 사용합니다.

변경의 표준 : : 할당 :: 직관적와 수정할 수없는 방법으로 유효한 코드를 깨고, 무엇보다도, 성병 :: initializer_list 생성자 오버로드를 우선 순위를 줄 것이다 목록 초기화 를 사용하는 구성 -이있을 것 없음 emplace_back에 생성자가 std :: initializer_list에 의해 선점 되었으나 기본적으로 이 푸시 백을 다시 구현하지 않고 액세스했습니다.

std::vector<std::vector<int>> v; 
v.emplace_back(3, 4); // v[0] == {4, 4, 4}, not {3, 4} as in list-initialization 

제안 타협 표준 : is_constructible, 직접 초기화가 잘 형성되어 있는지 여부를 테스트 와 SFINAE을 사용하는 것입니다. is_constructible이 false 인 경우 대체 std :: allocator :: construct overload가 선택되어 목록 초기화가 사용됩니다. 목록 초기화는 항상 직접 초기화에 해당하므로 직접 초기화 과부하가 실패 할 수 없으므로 목록 초기화 (균일 초기화)가 항상 사용 된 것처럼 진단 메시지가 표시됩니다 ( ).

나는이 계획에서 틈을 드러내는 두 개의 코너 케이스를 볼 수 있습니다. 하나는 의 stplace :: initializer_list를위한 인수가 생성자를 만족시킬 때 (예 :의 값을 emplace-insert하는 경우) 이 발생합니다.해결 방법은 v.emplace_back (std :: initializer_list (3, 4))에서와 같이 std :: initializer_list 유형을 명시 적으로 지정하는 것입니다. 이것은 과 일치하기 때문에 std :: initializer_list와 같은 의미가 추론됩니다. 은 실제 문제가 아닙니다.

다른 경우는 집합 초기화를위한 인수가 생성자를 만족할 때입니다. 은 생성자를 만족합니다. 집계에는 사용자가 정의한 생성자를 사용할 수 없기 때문에 의 첫 번째 비 정적 데이터 멤버는 집계 유형에서 암시 적으로 변환 가능해야하고 은 초기화 프로그램 목록에 요소가 하나 있어야합니다. 해결 방법은 에 두 번째 구성원의 초기화 프로그램을 제공하는 것입니다. 은 하나의 비 정적 데이터 멤버가있는 집계를 집계 자체 유형으로 변환 할 수있는 형식으로 변환하는 것은 불가능합니다. 이 는 허용되는 작은 구멍처럼 보입니다.

+2

완벽하게 구문 중괄호 init 목록을 전달하는 언어 supporrt 유형을 만들 수 있습니다. 그렇다면 그냥 emplace_back ({a, b, ...})이라고 말할 수 있습니다. –

+4

@ JohannesSchaub-litb : IMHO, std :: initializer_list가 무엇을 가져야하는지 더 좋아합니다. 그러나'std :: allocator'를 간단하게 수정하면 문제가 해결 될 것입니다. – Potatoswatter

+0

vvuser가 사용자 정의 alloc으로 벡터를 제거하고 emplace_back (1,2, alloc)을 작성하면 어떨까요? 그것을 ({1,2}, alloc)로 전달하는 것을 어떻게 알 수 있습니까? 할당 자 해킹이 더 많은 것을 깨뜨리는 것. 적절한 해결책을 찾아야한다. –

관련 문제