2014-11-03 2 views
10

왜 첫 번째 함수 호출 (cm(car);)이 첫 번째 함수에 바인딩됩니까?첫 번째 함수 호출이 첫 번째 함수에 바인딩되는 이유는 무엇입니까?

두 번째 호출은 두 번째 함수에 바인딩된다는 점을 알고 있습니다. 두 번째 호출은 둘 다 완벽하게 일치하지만 템플릿이 아니기 때문에 두 번째 함수에 바인딩된다는 것을 알고 있습니다.

제 함수로서, 고정 된 어레이 길이 비 주형으로 정의되는 경우, 다시이 (두 번째 전화가 모호한 그렇게 할 것이다) 제 하나 이상 선택된 얻는다보다

void cm(const char (&h)[8]) {cout << "const char (&)[8]" << endl;} 

.

코드 :

template<size_t N> void cm(const char (&h)[N]) 
    {std::cout << " const (&)[N] " << endl;} 

void cm(const char * h) 
    {cout << " const char * " << endl;} 

int main() 
{ 
    char car[] = "errqweq"; 
    const char ccar[] = "errqweq"; 
    cm(car); 
    cm(ccar); 
} 

출력 :

const (&)[N] 
const char * 

답변

2

는 메모리의 일부에, 실행시에, 때문에 문자열을 직접 코드로 작성 "errqweq는"읽기 전용이기 때문에 " 보호 된 "상수로 관리됩니다.

const char* ccar; 또는 const char ccar[];을 사용하여 가리키는 것이 맞습니다. const 지정자로 원래 "errqweq"를 보유한 메모리를 가리키고 있습니다. 컴파일러는 문자열이 수정되지 않도록합니다.

그러나보고에서 : 당신은 modificable 버퍼를 제공하기 위해 char car[] = "errqweq";

컴파일러 스택 복사 8 개 요소들의 어레이 (7 개 문자 + \ 0)을 생성 (는 CONST 수정없이 요청하는 등) 문자열을 "errqweq"로 초기화합니다 (즉 : intialize).

따라서 첫 번째 호출은 const char buffer[8]으로 안전하게 변환 된 char buffer[8] 인수를 사용합니다. 분명히 고정 된 크기의 배열은 상수 포인터가 필요한 "약한"바인딩 대신 템플릿과 가장 잘 일치합니다.

+0

글쎄, const char []가 스트링 리터럴로 그렇게 할 줄은 몰랐다. 나는이 경우 char []'처럼 행동 할 것이라고 생각했다. –

+0

답안의 마지막 단락에있는 논쟁은 부정확합니다. 그렇지 않습니까? – Columbo

4

첫 번째 호출은 함수 템플릿 전문화를 선택합니다. 더 나은 일치이기 때문입니다.
우리 모두 과부하 레이블을 보자 : (1), car는 참조 결합에 대한

template<size_t N> void cm(const char (&h)[N]) // (1) - the specialization 
    {std::cout << " const (&)[N] " << endl;} 

void cm(const char * h)       // (2) 
    {cout << " const char * " << endl;} 

합니다. 그것은 신원 변환 입니다. (2)의 경우 char* 의 배열 - 포인터 변환 car을 수행 한 후에는 char*
char const*이되도록 정규화 변환을 수행해야합니다.

표준 변환 시퀀스 S1

  • S1는 정규형의 전환 서열을 비교 S2의 적절한 시퀀스가 ​​(인 S2 경우 표준 변환 순서보다 더 나은 변환 시퀀스이다 : 즉, 지금이 호출되고 13.3.3.1에 의해 정의된다.1, 제외한 모든 Lvalue 변환; 아이덴티티 전환 서열
  • [...]

배열 투 포인터 변환이 된, 상관 비 식별 변환 시퀀스 시퀀스)이거나, 그렇지 않으면 해당되는 것으로 간주된다 Lvalue 변환이므로 두 번째 예제와 마찬가지로 여기서는 고려하지 않습니다. 자격 변환에는 고유 한 카테고리가 있습니다. 자격 조정. 따라서 (1)의 매개 변수로의 변환은 (2)의 매개 변수로의 변환의 하위 순서이다 : 첫 번째는 신원 변환이고 두 번째는 자격 변환이고, 위 단락에 따르면 신원 변환은 다음의 하위 순서이다. 모든 비정품 변환. 그래서 (1)이 선택됩니다.

이미 언급했듯이 두 번째 경우에도 전환율이 동일합니다. 위의 인용문은 (2) s 매개 변수로의 변환이 (1) 매개 변수로의 변환의 하위 순서가 아니기 때문에 작동하지 않습니다. 따라서 [over.match.best]/1이 적용됩니다. 이러한 정의 감안

, 실행 가능한 기능 F1 모든 인수 I 들어 ICSI (F1)이 ICSI (F2)보다 더 변환 순서가 아닌 경우 다른 가능한 기능 F2보다 나은 기능으로 정의하고,

  • 컨텍스트는 사용자 정의 된 변환에 의해 초기화가 아닌 그 경우 다음 일부 인수 J위한
    • 는 ICSj (F1)은 ICSj (F2)보다 더 나은 변환 시퀀스, 또는 [...] , 그렇지 않은 경우
    • F1 비 템플릿 함수이며 F2
  • 그래서 (2) 중 하나가 선택 함수 템플릿 특수화이다. 함수 템플리트가 템플리트가 아니고 매개 변수가
    char const (&)[8] 인 함수는 모호합니다 (as Clang correctly says).


    1 [over.ics.ref]/1

    참조 타입의 파라미터가 인자의 발현에 직접적으로 (8.5.3)를 결합

    암시 적 변환 시퀀스 인수 표현식이 매개 변수 유형의 파생 클래스 인 유형이 아닌 경우 변환입니다.이 경우 암시 적 변환 시퀀스는 파생 - 기반 변환 (13.3.3.1)입니다.

    [dcl.init.ref]/5 (8.5.3에있는) (즉, 이니셜 식으로부터 임시 생성 및 초기화하는) 마지막을 제외한 모든 경우에

    , 참고는 에 직접적으로을 이니셜 라이저 표현식에 바인드합니다.


    2 [conv.array]

    좌변 또는 "N T 배열"형태의 r- 수치 또는 "T의 경계 알 어레이"는 prvalue로 전환시킬 수있다 유형 "포인터가 T"이어야합니다. 결과는 배열의 첫 번째 요소를 가리키는 포인터입니다.

    T은 cv-qualified 일 수 있으며 따라서 pointee의 유형도 될 수 있습니다. 여기 Tchar이므로 포인터는 char =>char*의 포인터 유형입니다.

    +0

    "binds directly"는 8.5.3에 의해 정의 된 것처럼 보이지 않습니다. const가 아닌 배열을 const 레퍼런스에 바인드하는 것이 "직접 바인드 (binds directly)"로 간주된다는 말입니까? –

    +0

    @MattMcNabb 이것은 많은 사람들을 혼란스럽게 할 수 있으므로 각주를 추가했습니다. :) (그것은 정의되어있다, 나의 각주를 보아라) – Columbo

    +0

    AH 나는 그것을 간과했다. 따라서 임시 참조가 포함되지 않은 참조 바인딩을 의미합니다. –