std :: initializer_list가 기본 제공 언어가 아닌 이유는 무엇입니까?


96

std::initializer_list핵심 언어가 내장되어 있지 않은 이유는 무엇 입니까?

C ++ 11의 매우 중요한 기능이지만 자체 예약 된 키워드 (또는 유사)가없는 것 같습니다.

대신, initializer_list그건 단지 특별한 암시가 표준 라이브러리에서 템플릿 클래스 매핑 새로운에서 보강-초기화리스트 {...} 컴파일러에 의해 처리하는 것 구문을.

처음에이 솔루션은 상당히 엉망 입니다.

이것이 C ++ 언어에 대한 새로운 추가가 이제 구현되는 방식 입니까? 핵심 언어가 아닌 일부 템플릿 클래스의 암시 적 역할 에 의해 구현 됩니까?


다음 예를 고려하십시오.

   widget<int> w = {1,2,3}; //this is how we want to use a class

새로운 클래스가 선택되는 이유 :

   widget( std::initializer_list<T> init )

다음 아이디어 와 유사한 것을 사용하는 대신 :

   widget( T[] init, int length )  // (1)
   widget( T... init )             // (2)
   widget( std::vector<T> init )   // (3)
  1. const여기저기서 추가 할 수 있습니다.
  2. 언어에 이미 세 개의 점이 존재합니다 (var-args, 이제 가변 템플릿), 구문을 재사용하지 않는 이유 (그리고 내장 된 것처럼 느끼게 함 )
  3. 기존 컨테이너 만 추가 const하고&

그들 모두는 이미 언어의 일부입니다. 나는 첫 번째 아이디어를 세 개만 썼고 다른 많은 접근 방식 이 있다고 확신합니다 .


26
표준위원회는 새로운 키워드를 추가하는 것을 싫어 합니다!
Alex Chamberlain 2013 년

11
이것은 이해하지만, 언어를 확장하는 방법에 많은 가능성이 (가 키워드 그냥 예를 들어했다 )
emesx

10
std::array<T>는보다 '언어의 일부'가 아닙니다 std::initializer_list<T>. 그리고 이것들은 언어가 의존하는 유일한 라이브러리 구성 요소가 아닙니다. 참조 new/ delete, type_info다양한 예외 유형, size_t
bames53

6
@Elmes : const T(*)[N]작동 방식과 매우 유사하게 작동하기 때문에을 제안했을 것 std::initializer_list입니다.
Mooing Duck 2013 년

1
이것은std::array또는 정적 인 크기의 배열이 덜 바람직한 대안에 대한 대답 입니다.
boycy

답변:


48

std네임 스페이스에 정의 된 유형을 반환하는 "핵심"언어 기능의 예가 이미있었습니다 . typeid반환 std::type_info하고 (아마도 점을 늘리면)를 sizeof반환합니다 std::size_t.

전자의 경우 소위 "핵심 언어"기능을 사용하려면 이미 표준 헤더를 포함해야합니다.

이제 이니셜 라이저 목록의 경우 객체를 생성하는 데 키워드가 필요하지 않으며 구문은 상황에 맞는 중괄호입니다. 그 외에는 type_info. 개인적으로 나는 키워드의 부재가 그것을 "더 해키"하게 만든다고 생각하지 않습니다. 약간 더 놀랍지 만, 목표는 이미 집계에 허용 된 것과 동일한 중괄호 이니셜 라이저 구문을 허용하는 것이 었습니다.

그렇습니다. 앞으로이 디자인 원칙을 더 많이 기대할 수 있습니다.

  • 새로운 키워드없이 새로운 기능을 도입 할 수있는 경우가 더 많이 발생하면위원회에서이를 채택합니다.
  • 새로운 기능에 복잡한 유형이 필요한 경우 해당 유형은 std내장이 아닌에 배치됩니다 .

그 후:

  • 새 기능에 복잡한 유형이 필요하고 새 키워드없이 도입 할 수있는 경우 여기에서 얻을 수 있습니다. 새 키워드가없는 "핵심 언어"구문이며 std.

내 생각에는 C ++에서 "핵심 언어"와 표준 라이브러리 사이에 절대적인 구분이 없다고 생각합니다. 그것들은 표준의 다른 장이지만 각각은 다른 장을 참조하며 항상 그렇습니다.

C ++ 11에는 람다 가 컴파일러에 의해 생성 된 익명 형식 을 가진 개체를 도입하는 또 다른 접근 방식이 있습니다 . 이름이 없기 때문에 네임 스페이스에 전혀없고 std. 하지만 이니셜 라이저 목록에는 적합한 접근 방식이 아닙니다. 하나를 허용하는 생성자를 작성할 때 유형 이름을 사용하기 때문입니다.


1
이러한 암시 적 유형의 역할 때문에이 구분이 불가능한 것 같습니다 (mailny?) . type_info그리고 size_t좋은 인수입니다 .. 잘 size_ttypedef입니다 .. 그래서 이것을 건너 뛰자. 차이 type_infoinitializer_list상기 제는 결과 있다는 명백한 연산자, 및 두 번째 내재 컴파일러 행동. 또한 이미 존재하는 일부 컨테이너로 대체 initializer_list 될 수 있는 것 같습니다 . 또는 더 나은 : 사용자가 인수 유형으로 선언하는 모든 것!
emesx 2013 년

4
... 아니면 당신이 생성자를 작성하면되는 간단한 이유가 될 수도 vector그 취하는 array다음에서 벡터를 구축 할 수 있는 단 하나의 이니셜 라이저 목록 구문에 의해 생성하지 않을 권리 유형의 배열입니다. 어떤 array에서 컨테이너를 구성하는 것이 나쁜 것인지는 모르겠지만 새로운 구문을 도입하는위원회의 의도는 아닙니다.
Steve Jessop 2013 년

2
@Christian : 아니요, std::array생성자도 없습니다. 이 std::array경우는 단순히 집계 초기화입니다. 또한이 토론이 조금 길어지고 있으니 Lounge <C ++> 채팅방에 함께 하시길 환영합니다.
Xeo

3
@ChristianRau : Xeo는 이니셜 라이저 목록이 생성 될 때 요소가 복사됨을 의미합니다. 이니셜 라이저 목록을 복사해도 포함 된 요소는 복사되지 않습니다.
Mooing Duck 2013 년

2
@Christian List-initialisation은 initializer_list를 의미하지 않습니다. 좋은 직접 초기화 또는 집계 초기화를 포함하여 여러 가지가 될 수 있습니다. 그들 중 어느 것도 initializer_list를 포함 하지 않습니다 (그리고 일부 는 그렇게 작동 하지 않습니다 ).
R. Martinho Fernandes 2013 년

42

C ++ 표준위원회는 새 키워드를 추가하지 않는 것을 선호하는 것 같습니다. 이는 기존 코드를 손상시킬 위험을 증가시키기 때문일 것입니다 (레거시 코드는 해당 키워드를 변수, 클래스 또는 다른 이름으로 사용할 수 있음).

또한 std::initializer_list템플릿 컨테이너로 정의하는 것은 매우 우아한 선택 인 것 같습니다. 키워드라면 기본 유형에 어떻게 액세스할까요? 어떻게 반복 하시겠습니까? 새로운 연산자도 많이 필요하며 표준 컨테이너로 할 수있는 것과 동일한 작업을 수행하기 위해 더 많은 이름과 더 많은 키워드를 기억해야합니다.

std::initializer_list다른 컨테이너로 취급하면 이러한 것들과 함께 작동하는 일반 코드를 작성할 수 있습니다.

최신 정보:

그렇다면 기존의 조합을 사용하는 대신 새로운 유형을 도입하는 이유는 무엇입니까? (댓글에서)

우선 다른 모든 컨테이너에는 요소를 추가, 제거 및 대체하는 메서드가 있으며 이는 컴파일러 생성 컬렉션에는 바람직하지 않습니다. 유일한 예외는 std::array<>고정 된 크기의 C 스타일 배열을 래핑하므로 유일하게 합리적인 후보로 남을 것입니다.

그러나 니콜 올가미가 올바르게 코멘트 지적 간의 또 다른 중요한 차이점 std::initializer_list및 (을 포함한 모든 다른 표준 컨테이너 std::array<>) 후자 것들이있다이다 값 의미를 동시에 std::initializer_list갖는 참조 시맨틱 . 복사 std::initializer_list예를 들어, 여기에 포함 된 요소의 사본을 발생하지 않습니다.

또한 (다시 한 번 Nicol Bolas의 호의) 중괄호 초기화 목록을위한 특수 컨테이너를 사용하면 사용자가 초기화를 수행하는 방식에 과부하가 걸릴 수 있습니다.


4
그렇다면 기존의 조합을 사용하는 대신 새로운 유형을 도입하는 이유는 무엇입니까?
emesx 2013 년

3
@elmes : 사실 std::array. 그러나 컴파일 타임 배열 std::arraystd::initializaer_list래핑 하면서 메모리를 할당합니다 . 차이점이라고 생각 char s[] = "array";하고 char *s = "initializer_list";.
rodrigo 2013 년

2
그리고 일반 유형이기 때문에 오버로딩, 템플릿 전문화, 이름 장식 등은 문제가되지 않습니다.
rodrigo 2013 년

2
@rodrigo : std::array메모리를 할당하지 않습니다. 평범 T arr[N];하고 백업하는 것과 같은 것입니다 std::initializer_list.
Xeo

6
@Xeo : 동적 힙이 아닌 다른 곳에 메모리를 T arr[N] 할당 합니다 std::array. 그러나 비어 initializer_list있지 않은 것은 사용자가 구성 할 수 없으므로 분명히 메모리를 할당 할 수 없습니다.
rodrigo 2013 년

6

이것은 새로운 것이 아닙니다. 예를 들어, for (i : some_container)에 의존하는 특정 방법 또는 독립형 기능의 존재some_container클래스입니다. C #은 .NET 라이브러리에 더 많이 의존합니다. 사실, 이것은 언어 사양을 복잡하게하지 않고도 클래스를 일부 언어 구조와 호환되도록 만들 수 있기 때문에 이것은 매우 우아한 솔루션이라고 생각합니다.


2
클래스 또는 독립형 beginend메서드의 메서드. 이것은 약간 다른 IMO입니다.
emesx 2013 년

3
맞나요? 다시 한 번 코드의 특정 구성에 의존하는 순수한 언어 구성이 있습니다. 예를 들어 새 키워드를 도입하여 수행되었을 수도 있습니다.iterable class MyClass { };
Spook

하지만 원하는 곳에 메소드를 배치하고 원하는대로 구현할 수 있습니다. 일부 유사점이 있습니다. 동의합니다! 이 질문에 관한 initializer_list생각
emesx

4

이것은 실제로 새로운 것이 아니며 얼마나 많은 사람들이 지적 했는가?이 관행은 C ++에 있었고 C #에도 있습니다.

Andrei Alexandrescu는 이것에 대해 좋은 점을 언급했습니다. 가상의 "핵심"네임 스페이스의 일부로 생각할 수 있습니다. 그러면 더 의미가있을 것입니다.

따라서 실제로는 다음과 같습니다. core::initializer_list , core::size_t, core::begin(), core::end()과에 이렇게. std네임 스페이스 내부에 핵심 언어 구조 가있는 것은 불행한 우연입니다 .


2

표준 라이브러리에서 완벽하게 작동 할뿐만 아니라 표준 라이브러리에 포함되었다고해서 컴파일러가 영리한 트릭을 할 수 없다는 의미는 아닙니다.

모든 경우에 불가능할 수도 있지만이 유형은 잘 알려져 있거나 간단한 유형입니다. initializer_list 하고 초기화 된 값이 무엇인지에 대한 메모리 이미지를 갖게됩니다.

int i {5};에 해당 될 수 있습니다 int i(5);또는 int i=5;심지어 intwrapper iw {5};어디 intwrapper사소한 생성자가 복용하는 int 이상의 클래스 래퍼 간단한이다initializer_list


실제로 이와 같은 "영리한 트릭"을 수행하는 컴파일러의 재현 가능한 예가 있습니까? as-if 하에서 추론 할 수 있지만 실증을보고 싶습니다.
underscore_d

컴파일러 최적화의 개념은 컴파일러가 코드를 동등한 코드로 변환 할 수 있다는 것입니다. 특히 C ++는 "무료"추상화를위한 최적화에 의존합니다. 표준 라이브러리에서 코드를 대체하는 아이디어는 일반적입니다 (gcc 내장 목록 gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html 참조 ).
Paul de Vrieze

사실, int i {5}어떤 std::initializer_list것이 든 관련된 당신의 생각 은 잘못되었습니다. int생성자 복용이 없다 std::initializer_list(가), 그래서 5단지 그것을 구성하기 위해 직접 사용됩니다. 따라서 주요 예는 관련이 없습니다. 수행 할 최적화가 없습니다. 그 외에도 std::initializer_list컴파일러가 '가상'배열을 생성하고 프록시하기 때문에 최적화를 선호 할 수 있지만 컴파일러의 '마법'부분이므로 일반적으로 최적화 프로그램이 예쁜 배열로 영리한 작업을 수행 할 수 있는지 여부와는 별개입니다. 2 개의 반복자를 포함하는 둔한 객체
underscore_d

1

그것은 단지 라인, 도서관에서 완전히 구현 될 수 있기 때문에 핵심 언어의 일부가 아니다 operator newoperator delete. 컴파일러를 더 복잡하게 만들면 어떤 이점이 있습니까?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.