2017-09-06 2 views
15

균일 한 초기화 중에 쉼표를 사용하면 의미가 어떻게 달라 집니까? 균일 한 초기화의 쉼표 뒤

std::vector<std::size_t> v1{5, }; // allowed syntax 
std::vector<std::size_t> v2{10}; 

나는 컴파일러 대신 std::vector::vector(std::size_t, const std::size_t &)std::vector::vector(std::initializer_list<std::size_t>) 생성자를 선택하거나 언급 한 구문과 다른 트릭이 존재하게 쉼표를 후행 사용할 수 있습니까?

검색에 사용할 수 있습니까? std::initializer_list - 생성자 오버로드가 있습니까?

다음 코드를 고려할 때 어떤 생성자를 선택해야합니까?

struct A { A(int) { ; } A(double, int = 3) { ; } }; 
A a{1}; 
A b{2, }; 

이 코드 is accepted by gcc 8A(int)는 두 경우 모두 선택됩니다.

+0

첫 번째 단락 ('std :: initializer_list'-constructor)은 항상 s입니다. 선출. https://wandbox.org/permlink/Yy6VtcK5ISCbzZJp – songyuanyao

+0

어쨌든'v2 {...}'가 어떤 생성자를 호출 할 이유는 없지만'std :: initializer_list'를 취하는 것은 ....'v2 (. ..)'std :: vector :: vector (std :: size_t ...)를 호출 할 것입니다. – jpo38

+0

@songyuanyao 그렇습니다. 단항 및 2 진수를 갖는 생성자와 기본 함수 매개 변수 이니셜 라이저가있는 생성자가있는 경우에는 어떻게 될까요? 다른 상황? 생각할 수있는 모든 경우에 * 어떤 의미 론적 차이점이 있습니까? – Orient

답변

9

첫 번째로 C++ 문법 규칙은 braced-init-list에 대한 후행 ,을 선택적으로 만듭니다. 선언되는 식별자에 대한 초기 값을 지정할 수 있습니다 dcl.init/1

선언자가 말을 인용합니다. 식별자는 초기화되는 변수를 지정합니다. [dcl.init] 의 나머지 부분에서 설명하는 초기화 프로세스는 함수 매개 변수 ([expr.call]) 초기화 또는 반환 값 초기화 ([expr.call] ) 초기화와 같은 다른 구문 컨텍스트 ( )에 의해 지정된 초기화에도 적용됩니다. stmt.return]).

initializer: 
    brace-or-equal-initializer 
    (expression-list) 
brace-or-equal-initializer: 
    = initializer-clause 
    braced-init-list 
initializer-clause: 
    assignment-expression 
    braced-init-list 
braced-init-list: 
    { initializer-list ,opt } 
    { designated-initializer-list ,opt } 
    { } 

둘째, 당신은 거의 오버로드 확인 시스템을 무시할 수 없습니다. 그러한 구문을 사용하는 경우 항상 std::initializer_list 생성자가 사용되며 해당 std::initializer_list 생성자를 사용할 수 있습니다.

dcl.init.list/2 : 첫 파라미터 타입 STD 인 경우

생성자는 초기화리스트 생성자 :: 일부 가능 CV 수식 표준 : initializer_list에 initializer_list 또는 레퍼런스 유형 E 및 다른 매개 변수가 없으면 다른 모든 매개 변수는 기본 인수가 입니다. [참고 : 초기화 프로그램 목록 생성자는 목록 초기화 ([over.match.list])의 다른 생성자보다 선호됩니다.


인쇄 Using InitList 아래 프로그램 : 5 유형 int의 문자라는 사실에도 불구하고

#include <iostream> 
#include <initializer_list> 

struct X{ 
    X(std::initializer_list<double>){ std::cout << "Using InitList\n"; } 
    X(int){ std::cout << "Using Single Arg ctor\n"; } 
}; 

int main(){ 
    X x{5}; 
} 

, 그것은 그것부터 단일 인수 생성자를 선택하는 감각을 했어야 완벽하게 일치; std::initializer_list<double> 생성자는 double의 목록을 원합니다. 그러나 규칙은 이니셜 라이저 목록 생성자이기 때문에 std::initializer_list<double>을 선호합니다. 이 표준 : initializer_list 아무 오버로드가 없거나 어떤 경우에 ", 아래의 코멘트에 대한 응답으로

#include <iostream> 
#include <initializer_list> 

struct Y{ 
    Y(std::initializer_list<char>){ std::cout << "Y Using InitList\n"; } 
    Y(int, int=4){ std::cout << "Y Using Double Arg ctor\n"; } 
}; 

int main(){ 
    Y y1{4777}; 
    Y y2{577,}; 
    Y y3{57,7777}; 
} 

: 결과

, 심지어 프로그램은 아래에 있기 때문에 축소 변환 실패 첫 번째 생성자의 매개 변수가 아닙니까? "- 오버로드 해상도로 선택하지 않았습니다. 데모 :

#include <iostream> 
#include <initializer_list> 

struct Y{ 
    Y(int, std::initializer_list<double>){ std::cout << "Y Using InitList\n"; } 
    Y(int, int=4){ std::cout << "Y Using Double Arg ctor\n"; } 
}; 

int main(){ 
    Y y1{4}; 
    Y y2{5,}; 
    Y y3{5,7}; 
} 

인쇄 :

Y Using Double Arg ctor 
Y Using Double Arg ctor 
Y Using Double Arg ctor 

가능한 초기화리스트 생성자이없는 경우, {initializer-list...,} 초기화는 거의 그 의미이며, dcl.init/16에 따라 다시 직접 초기화에 떨어진다 dcl.init/16

+0

OK 'std :: initializer_list'로 오버로딩을하지 않거나 첫 번째 생성자의 매개 변수가 아닌가? – Orient

+0

@ 원본, 업데이트 된 답변보기 – WhiZTiM

2

아니요. 쉼표는 컴파일 오류없이 사전 처리기 매크로 트릭이 작동하도록하는 양보입니다. 그것은 당신의 데이터 타입이나 그 크기에 대해서는 아무런 의미가 없다.