2014-12-10 6 views
12

내 질문은 배열 참조 매개 변수를 수락하는 두 개의 비 템플릿 함수간에 과부하 해결을 시도하는 매우 간단하고 짧은 코드와 관련이 있습니다. 질문은 다른 곳에 게시되었지만 템플릿 추론 컨텍스트에 게시되었습니다.템플릿이 아닌 컨텍스트에서 배열 참조 매개 변수에 대한 Initializer_list

#include <iostream> 

void foo (const int (&x) [3]) { std::cout << "3\n"; } 
void foo (const int (&x) [2]) { std::cout << "2\n"; } 

int main() 
{ 
    foo({1,2,3}); 
} 

그램 ++ 4.8.3 (내 생각)으로 연타 3.4하면서 , 유일한 생존을 첫 번째 기능을 선택이 코드는 foo에 대한 호출이 모호 말하는, 그것을 컴파일되지 않습니다 컴파일 (다음은 코드는 왜?).

옳은 일을하는 컴파일러는 무엇입니까?

clang은 두 번째 오버로드를 제거하는 코드도 컴파일하지 않습니다. initializer_list가 단순히 배열 참조를 초기화하는 것으로 받아 들여지지 않는 것처럼 보입니다.

이 버그가 있습니까?

+0

"그 소리가 코드를 컴파일하지 않습니다와 같은 의미 심지어 두 번째 과부하 제거 "- clang 3.4.2를 사용하여 명령 줄 옵션에'-std = C++ 11 '이 포함되어 있다면 (제 2의 과부하가 제거되면) . 어떤 버전과 호출이 실패합니까? – hvd

+0

맞습니다. 두 번째 오버로드를 제거한 후 플래그 -std = C++ 11을 잊어 버린 코드를 컴파일했습니다. 그 죄송합니다. – GSi

+0

이제 나는이 같은 오류를 피하기 위해 명령 별칭을 정의했다. – GSi

답변

5

나는 GCC의 행동이 더 유용하지만, 그것은의를 위해 올바른 행동을 연타 있다고 생각 C++ 11 :

13.3.3.1.5 목록 초기화 순서 [over.ics.list] 파라미터 타입 std::initializer_list<X> 또는 암시 X으로 변환 할 수 있고, 이니셜리스트의 모든 요소 「X 배열 "이면

2 암시 적 변환 시퀀스 X 상기리스트의 요소를 변환해야 최악의 변환은 .

이 변환 시퀀스는 배열 길이에 아무런주의를 기울이지 않습니다. 두 함수 모두 과부하는 ID 변환 인 암시 적 변환 시퀀스를 제공합니다. 둘 다 int의 배열에 대한 참조를 취하고 함수 인수의 각 요소는 int입니다.

과부하 해상도는 두 개의 정체성 변환을보고, 표준이 동일 순위의 전환을 충돌을 해결하기위한 몇 가지 예외를 가지고 있지만, 배열의 길이에 주목 아무도 없다 :

13.3. 3.2 순위 암시 적 변환 시퀀스 [over.ics.rank]

다음 규칙들 중 하나가 적용되지 않는 동일한 형태의 두 암시 적 변환 서열 3 구별 변환 시퀀스이다 :

다음에는 배열을 전혀 언급하지 않은 목록이옵니다.

Jonathan Wakely는 이후 변경되었다고 지적합니다. 귀하의 질문은 바로 그 변화를 촉발시킨 것이며, 해당 DR은 #1307입니다. C++ 14에서는 코드가 유효하지만 C++ 11에서는 유효하지 않습니다.

+1

매개 변수 유형은'std :: initializer_list'가 아니며 현재 작업중인 용지는 배열과'initializer_list'를 다른 단락으로 나누어 처리합니다. 배열 길이 : _ "매개 변수 유형이"NX 배열 "인 경우, 이니셜 라이저 목록이 정확히 N 개의 요소를 가지고 있거나 N이 요소보다 작고이고 X가 기본 구성 가능이면 모든 요소가 이니셜 라이저 목록은 암시 적으로 X로 변환 될 수 있지만 암시 적 변환 순서는 목록 요소를 X로 변환하는 데 필요한 최악의 변환입니다. "_ –

+0

@JonathanWakely"std :: initializer_list "또는"X의 배열 " "이고 매개 변수 유형이 배열 인 경우 더 최근의 논문의 문구를 확인하겠습니다. – hvd

+3

http://open-std.org/jtc1/sc22/wg21 /docs/cwg_defects.html#1307 –

4

DR 1232 이니셜 라이저 목록에서 참조 매개 변수에 대한 매개 변수가있는 호출 함수를 허용하도록 C++ 11이 변경되었습니다. (작업 보고서의 변경 내용은 N3262에 나와 있습니다.) 테스트 된 모든 컴파일러는 해당 규칙을 구현합니다.

DR1307 그런 다음 동일한 문구가 다시 변경되어 발견 된 모호성을 해결합니다.귀하의 코드는 GCC 및 EDG 컴파일러에서 허용되므로 Clang이 해당 DR을 아직 구현하지 않았다고 가정합니다.

DR이 해결 된 후에도 foo({1, 2})은 여전히 ​​모호하며 모든 컴파일러에서 거부됩니다. 그 이유는 {1, 2}는 (분명히)이 const int(&)[2] 매개 변수에 바인딩 할 수 있지만 int는 기본적으로 작도 때문에 그것은 또한 const int(&)[3] 매개 변수에 바인딩 할 수 있다는 것입니다, 그래서 {1, 2, int()}{1, 2, 0}

+0

"foo ({1, 2})는 여전히 모호합니다."- 확실합니까? "L1 - N1 T의 배열"로 변환하면 L2는 목록 초기화 시퀀스 L2보다 나은 변환 시퀀스가 ​​아닙니다. L2는 "N2 T 배열"유형으로 변환하고 N1은 더 작습니다 N2보다. " 'const int (&) [2]'오버로드에 찬성하여 그것을 해결 하시겠습니까? – hvd