IT Share you

C ++ 14에서 쌍 배열의 초기화에 여전히 이중 중괄호가 필요한 이유는 무엇입니까?

shareyou 2020. 11. 28. 13:14
반응형

C ++ 14에서 쌍 배열의 초기화에 여전히 이중 중괄호가 필요한 이유는 무엇입니까?


C ++ 14 표준을 사용하면 std::array중괄호 하나로 초기화 할 수 있습니다 ( http://en.cppreference.com/w/cpp/container/array 참조 ).

그러나 이것은 std::arraystd::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}};

컴파일러에는 구문을 해석하는 두 가지 방법이 있습니다.

  1. 전체 중괄호 초기화를 수행합니다. 즉, 가장 바깥 쪽 중괄호는의 집계 초기화를 참조하고 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}};
    

    집계 초기화로 잘 컴파일됩니다.

  2. (당신이 의미하는 방식입니다.) 중괄호 제거 초기화를 수행하므로 가장 안쪽 중괄호는 개별 쌍의 집계 초기화를위한 반면 내부 배열 표현에 대한 중괄호는 제거됩니다. 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.

참고URL : https://stackoverflow.com/questions/50598248/why-does-initialization-of-array-of-pairs-still-need-double-braces-in-c14

반응형