2011-03-02 5 views
34

어느 한 날 다음 코드를 이해하는 데 도움이패스 참조

#include <iostream> 

void foo(const char * c) 
{ 
    std::cout << "const char *" << std::endl; 
} 

template <size_t N> 
void foo(const char (&t) [N]) 
{ 
    std::cout << "array ref" << std::endl; 
    std::cout << sizeof(t) << std::endl; 
} 

int main() 
{ 
    const char t[34] = {'1'}; 
    foo(t); 

    char d[34] = {'1'}; 
    foo(d); 
} 

출력은

const char * 
array ref 
34 

왜 첫 번째 foo는이 const char * 버전을 호출 않습니다입니까? 참조 버전을 호출하려면 어떻게해야합니까?

+0

출력은 msvc – Marlon

+0

에서 나를위한'const char *, const char *'입니다. 출력은'const char *, array ref, 34'와'gcc-4.3.4' (http : //)입니다. ideone.com/ejyCS). – James

+1

@ user511274 - 흥미로운 질문 : –

답변

15

const char[N]에서 const char*으로의 변환은 "정확한 일치"(주로 리터럴을 쉽게 만들기 위해)로 간주되며 두 개의 정확히 일치하는 항목 중 템플릿없는 기능이 우선합니다.

enable_ifis_array을 사용하면 원하는대로 할 수 있습니다.


강제로 지저분한 방법이 될 수 있습니다

#include <iostream> 

template <typename T> 
void foo(const T* c) 
{ 
    std::cout << "const T*" << std::endl; 
} 

template <typename T, size_t N> 
void foo(const T (&t) [N]) 
{ 
    std::cout << "array ref" << std::endl; 
} 

int main() 
{ 
    const char t[34] = {'1'}; 
    foo(t); 

    char d[34] = {'1'}; 
    foo(d); 
} 

/* 
array ref 
array ref 
*/ 

내가 영업 이익은 char없는 몇 가지 일반적인 T을 한 것으로 인식하지만, 그럼에도 불구하고이 문제가 템플릿 인 하나 과부하에 누워 있음을 보여주고 다른 것은 아닙니다.

+1

어떻게해야합니까? 'foo()'의 두 번째 버전을 두 번째로 호출한다고 설명하겠습니까? – fouronnes

+1

@otibom :'char [N]'의 변환에는 같은 규칙이 없습니다. 'char [N]'과'const char *'는 완전히 일치하지 않습니다 : 변환 가능하지만 템플릿 함수는 더 쉽게 일치합니다. –

+0

@otibom 첫 번째 버전은 const가 아니지만 템플릿 버전은 const 배열 포인터를 사용합니다. – Lundin

5

템플릿이없는 수정 된 예제를 살펴 보겠습니다.

void foo(const char * c) 
{ 
    std::cout << "const char *" << std::endl; 
} 

void foo(const char (&t) [34]) 
{ 
    std::cout << "const char (&) [34]" << std::endl; 
} 

int main() 
{ 
    const char t[34] = {'1'}; 
    foo(t); 
} 

제 컴파일러는 오버로드 foo의 호출이 모호했다. 이는 배열에서 포인터로의 변환이 "정확한"변환 시퀀스로 간주되어 과부하 해결을위한 null 변환 시퀀스보다 우수하지 않기 때문입니다 (표준 섹션 13.3.3.1.1.)

원본 코드에서 템플릿 매개 변수 N은 34로 추론 될 수 있지만 템플릿이 아닌 foo(const char*)foo<34>(const char (&)[34])은 모두 과부하 해결로 간주됩니다. 어느 쪽도 변환 룰에 의해 다른 것보다 우수하지 않기 때문에, 비 템플릿 함수는 템플릿 함수를 능가한다.

문제를 해결하는 것은 까다로운 일입니다. is_array 헤더 (<type_traits>) 템플릿 (가능한 경우 C++ 0x 또는 부스트하지 않는 경우)이 도움이 될 것 같습니다.

+0

실제로 enable_if 및 is_array를 사용하여 원하는 것을 얻을 수 있습니다. –

+0

@Tomalak : C++ 03 및 Boost를 사용하는 간단한 방법이 있습니까? 예를 들어 설명해 보았습니다. 그런 다음 rvalue-references가 필요하다는 것을 알았습니다. rvalue-references는 질문의 태그에 포함되지 않았습니다. – aschepler

+0

@aschepler : 경기장 평준화와 관련된 접근 방식으로 답변을 업데이트했습니다. –

1

이것은 다양한 컴파일러에서 다른 것으로 보입니다.

Mircosoft와 Borland는 모두 const char * 버전을 사용하는 반면 GNU는 사용자가 설명한 결과를 제공합니다. 함수 호출에서 템플릿 인수를 추론

14.8.2.1는 [temp.deduct.call]

템플릿 인수 공제가 각을 비교하여 수행됩니다 : 여기

은 C++ 표준에서 미리보기입니다 함수 템플리트 의 해당 인수가 이면 으로 전화 (A)라고하는 매개 변수 유형 (P라고 함)을 입력하십시오.

P가 참조 유형이 아닌 경우

- A는 어레이 형 어레이 간 포인터 표준 변환에 의해 생성 된 포인터 타입 인 경우 (4.2)를 (A)의 장소에서 사용 유형 공제; 그렇지

- A가 함수 타입, 형태 추론하는 대신에 사용되는 함수 투 포인터 표준 변환 (4.3)에 의해 생성 된 포인터 타입 인 경우;

- A가 cv 한정 유형 인 경우 A 유형의최상위 수준 cv 한정자는 유형 공제에 대해 무시됩니다.

P가 Cv 한정 유형 인 경우 수준의 P 유형의 cv 한정자는 유형 공제에 대해 무시 된 입니다.

Argument:  t     d 
A:   char const[34]  char[34] 

과 매개 변수리스트를 P을 : P는 참조 타입 인 경우, P가 함 유형은 다음과

컴파일러는 A 목록을 작성한다 형태 추론에 사용되는

Parameter:  c     t 
P:   char const*  char const& t[N] 

기본적으로 컴파일러는 참조되지 않은 매개 변수를 선택해야합니다. GNU는 어떤 이유로 두 번째로 잘못했다.

+0

아니야, 그렇지 않아. 비 템플릿이 선호된다는 사실을 잊고 있습니다. MS와 Borland가 서로 다른 출력을 제공하면 비 호환입니다. 템플릿 유형 공제는 완전히 무의미합니다. –

+0

템플릿 공제 인수가 문제가되지 않습니다. 과부하 해결 방법은 다음과 같습니다. – aschepler