C ++ 14에서 쌍 배열의 초기화에 여전히 이중 중괄호가 필요한 이유는 무엇입니까?
C ++ 14 표준을 사용하면 std::array
중괄호 하나로 초기화 할 수 있습니다 ( http://en.cppreference.com/w/cpp/container/array 참조 ).
그러나 이것은 std::array
의 std::pair
.
작동하는 이유 :
std::pair<int, int> p { 1, 2 };
std::array<int, 3> a {1, 2, 3};
그러나 이것은 작동 하지 않습니다 .
std::array<std::pair<int, int>, 3> b {{1, 11}, {2, 22}, {3, 33}};
이것이 다시 작동하는 동안?
std::array<std::pair<int, int>, 3> b {{{1, 11}, {2, 22}, {3, 33}}};
또한 완료를 위해 오래된 배열의 초기화는 단일 중괄호로 작동합니다.
std::pair<int, int> c[3] {{1, 11}, {2, 22}, {3, 33}};
이것은 유명한 가장 짜증나는 구문 분석 과 다소 유사한 구문 분석 매복 성으로 보입니다 . 나는 무슨 일이 일어나고 있는지 의심합니다.
당신이 쓰면
std::array<std::pair<int, int>, 3> b {{1, 11}, {2, 22}, {3, 33}};
컴파일러에는 구문을 해석하는 두 가지 방법이 있습니다.
전체 중괄호 초기화를 수행합니다. 즉, 가장 바깥 쪽 중괄호는의 집계 초기화를 참조하고
std::array
가장 안쪽에있는 첫 번째 중괄호는std::array
실제 C-Array 인 내부 멤버 표현을 초기화합니다 .std::pair<int, int>
나중에 초기화 할 수 없기 때문에 컴파일에 실패합니다1
(모든 중괄호가 사용됨). clang은 정확히 다음을 나타내는 컴파일러 오류를 제공합니다.error: no viable conversion from 'int' to 'std::pair<int, int>' std::array<std::pair<int, int>, 3> a{{1, 11}, {2, 22}, {3, 33}}; ^
초기화 할 내부 멤버 집계가없는 경우에도이 문제가 해결됩니다.
std::pair<int, int> b[3] = {{1, 11}, {2, 22}, {3, 33}};
집계 초기화로 잘 컴파일됩니다.
(당신이 의미하는 방식입니다.) 중괄호 제거 초기화를 수행하므로 가장 안쪽 중괄호는 개별 쌍의 집계 초기화를위한 반면 내부 배열 표현에 대한 중괄호는 제거됩니다. rustyx의 대답 에서 올바르게 지적했듯이 이러한 모호성
std::pair
이 없더라도 집계 유형이 없기 때문에 중괄호 제거 규칙이 적용되지 않으므로 프로그램은 여전히 잘못 구성됩니다.
컴파일러는 옵션 1을 선호합니다. 추가 중괄호를 제공하여 전체 중괄호 초기화를 수행하고 구문상의 모호성을 제거합니다.
C ++ 14 중괄호 제거 규칙 은 부분 집계 초기화에만 적용됩니다.
예를 들어 다음과 같이 작동합니다.
std::array<std::array<int, 3>, 3> a{1, 11, 2, 22, 3, 33};
여기서 집계 집합은 추가 중괄호없이 목록 초기화 될 수 있습니다.
그러나 집계std::pair
가 아니므로 (생성자가 있음) 규칙이 적용되지 않습니다.
즉, 중괄호 제거 규칙이없는 std::array
자체는 내부에 배열이있는 집계이므로 목록 초기화 를 위해 추가 중괄호 세트가 필요합니다 . 클래스 템플릿 array
은 다음과 같이 구현됩니다.
template<typename T, std::size_t N>
struct array {
T elems[N];
};
중괄호 제거 규칙없이 목록을 초기화 하려면 elems
멤버 에 도달하기위한 추가 중괄호 세트가 필요합니다 .
이중 중괄호가 없으면 문이 모호합니다. 다음 코드를 고려하십시오.
std::array<std::pair<int, int>, 1> a = {{ {1, 2} }};
std::array<int, 2> b = { {1, 2} };
첫 번째 정의에 이중 중괄호가 없으면 컴파일러는에 { {1,2} }
대한 스칼라 초기화 목록으로 처리 합니다 array<int, 2>
. 컴파일러가 내부 목록도 집계 초기화 (스칼라 초기화와 비교)되어 있음을 인식 하도록 명시 적 중첩 중괄호 초기화 목록 을 선언해야합니다 .std::pair
이론적으로 std::array
는 집계 초기화로 초기화해야합니다. 그래서 실제로 이것은 :
std::array<int, 3> a {1, 2, 3};
이에 대한 구문 설탕입니다.
std::array<int, 3> a {{1, 2, 3}};
보시다시피, 첫 번째에서는 값으로 배열을 초기화하는 것처럼 보이지만 실제로는 중괄호로 묶인 초기화 목록을 사용한 집계 초기화입니다. 이것은 두 번째 상황의 하루처럼 분명합니다. 그래서 그것은 우선입니다.
좋아, 왜 이것이 작동하지 않습니까?
std::array<std::pair<int, int>, 3> b {{1, 11}, {2, 22}, {3, 33}};
Well, simply put - the compiler can't distinguish what type of syntax You are using to initialize the array. {1, 11}
can be interpreted both as initializer list and use the first version or it can be interpreted as a pair and go with the second version.
This code:
std::array<std::pair<int, int>, 3> b {{{1, 11}, {2, 22}, {3, 33}}};.
removes ambiguity.
Source: http://en.cppreference.com/w/cpp/language/aggregate_initialization
I'm going to guess here.
The initializer list for std::array<T,n>
should be a list of T
(or trivially constructable to T
). So you could do
std::array<std::pair<int,int>,3> b { std::pair{1,11}, std::pair{2,22}, std::pair{3,33} };
but that is tediously verbose. In order to get the conversion to std::pair<int,int>
you want, you need to provide an initializer list, so
std::array<std::pair<int,int>,3> b {
{ // element 1
{ // initialize from:
{ 1,11 } // std::initializer_list
}
},
...
};
I can't defend this further, but note that std::vector<T, Allocator>::vector( std::initializer_list<T>, const Allocator& alloc=Allocator())
is defined but std::array<T,n>::array( std::initializer_list<T> )
is not. Neither is std::pair<U,T>::pair( std::initializer_list<??> )
defined.
'IT Share you' 카테고리의 다른 글
파이썬에서 객체에 속성을 추가 할 수없는 이유는 무엇입니까? (0) | 2020.11.28 |
---|---|
멤버 함수와 함께 std :: bind를 사용하여이 인수에 대해 개체 포인터를 사용합니까? (0) | 2020.11.28 |
좋은 HAML-> ERB / HTML 변환기가 있습니까? (0) | 2020.11.28 |
toLowerCase의 NullPointer이지만 그 방법은 어디에도 사용하지 않습니다. (0) | 2020.11.28 |
Team Foundation Server에서 오프라인으로 작업 (0) | 2020.11.28 |