2013-04-07 20 views
3

누군가가 내게이 이론을 말해 줄 수 있습니까?생성자 및 initializer_list

마지막 호출이 컴파일되지 않는 이유는 무엇입니까?

test.cc: In function ‘int main()’: test.cc:15:12: error: too many braces around initializer for ‘int’ [-fpermissive] test.cc:15:12:

error: invalid conversion from ‘’ to ‘int’ [-fpermissive] test.cc:9:6: error: initializing argument 1 of ‘void f(std::initializer_list)’ [-fpermissive] test.cc:15:12:

error: aggregate value used where an integer was expected

는 나도 C++ 11 g ++ 4.7이 깨진 생각합니다. 감사합니다.

#include <initializer_list> 

class A { 
    public: 
    A(const std::initializer_list<int>) {} 
}; 

void f(const std::initializer_list<int>) {} 

int main() { 
    A({1}); // Compile OK 
    f({1}); // Compile OK 
    A({{{1}}}); // Compile OK 
    //f({{{1}}}); // Compile Error. 
} 
+0

감사합니다. 나는 C++ 11의 stardard 헤더 initializer_list에 대해 이야기하고있다. – yufanyufan

+0

흥미 롭습니다. Clang은 두 경우 모두 여분의 괄호에 대한 경고를 던집니다. – soon

답변

2

다음은 GCC가 생각하는 것입니다.

이것은 1 줄의 추가 줄과 번호가 매겨진 재미있는 줄이있는 프로그램입니다.

int main() { 
    A({1}); // 1. Compile OK 
    f({1}); // 2. Compile OK 
    A{{1}}; // 3. Compile OK, equivalent to 1. 
    A({{{1}}}); // 4. Compile OK 
    //f({{{1}}}); // 5. Compile Error. 
} 

왜 GCC가 5를 컴파일하지 않고 4를 컴파일합니까?

명확성을 위해

는, # 4의 건설을 실제로 선언 뭔가를한다고 가정

A a{{{1}}}; // 4a. Compile OK 

{{1}}이다 생성자의 인수가 A에 암시 적으로 변환 경우 GCC가 묻습니다. 그래서입니다 :

A{{1}} 

{{1}}에서 유효한 변환 A 수 있나요? 그렇습니다 - 당 3입니다.

이 추론은 물론 # 5에는 적용되지 않습니다. 따라서 오류.

당신이 4 번을 받아들이에서 GCC를 중지 할 경우, 노골적인 가능 생성자함으로써 수 있도록 변환 블록 :

error: converting to ‘A’ from initializer list would use explicit constructor ‘A::A(std::initializer_list<int>)’ 
+0

f ({1})와 f ({{1}}) 모두 오류없이 컴파일된다는 것을 알게되었습니다. 그들 사이의 차이점은 무엇입니까? – yufanyufan

+0

'{{1}} '의 컨스트럭터 변환에 대한 어색한 설명이 어딘가에 있지만 어쨌든 요하네스는 시가를 얻습니다. 그의 말은 "두 번째는 반복적으로 이니셜 라이저 목록에 간다." 아마도'f ({{1}})'이 괜찮은 이유를 설명 할 것입니다.하지만 그에게 연기 할게요 –

+0

첫 번째 중괄호는 init 목록 용이고 두 번째 중괄호는 int 용입니다. –

2

: 그럼 # 4 오류를 줄 것이다

class A { 
    public: 
    explicit A(const std::initializer_list<int> il) {} 
}; 

을 A {1}은 int를 초기화 할 수 있습니다. {{1}}은 아마도 그렇게해서는 안됩니다 - 그위원회에 대한 결함 보고서가 있습니다. GCC는 그것을 금지하고 clang은 현재 중복 중괄호에 대한 경고를 내보내는 경향이 있습니다.

X가 복사 또는 이동 생성자가있는 클래스 인 경우 X ({...})는 그 중 하나를 호출 할 수 있습니다. X {...}도 마찬가지지만 사용자 정의 변환 (복사 또는 이동 생성자의 경우)을 허용하지 않도록 제한됩니다.

이제 A ({{{1}}})로 첫 번째 중괄호가 복사/이동 생성자에 의해 소비됩니다. 두 번째는 이니셜 라이저 목록으로 재귀 적으로 이동합니다. 세 번째 요소는 포함 된 int로 이동합니다.

표준에 따르면, 중괄호를 하나 더 추가하면 A ({{{{}}})에 대해 중단됩니다. 두 번째 중괄호는 A의 복사/이동 생성자에 의해 소비되어야하지만 사용자 정의 변환 시퀀스가 ​​필요하기 때문입니다. A {{{{1}}}에 대해서도 동일하게 적용됩니다.이 이유도 잘못되었습니다.