2011-10-17 1 views
6

왜 배열이 템플릿 함수의 포인터로 쇠퇴하는지 이해할 수 없습니다.왜 배열이 템플릿 함수의 포인터에 부패합니까?

다음 코드를 살펴보면 : 매개 변수가 강제로 참조 (함수 f1) 일 때 감쇠되지 않습니다. 다른 함수 f에서는 부패합니다. 함수 f의 T 타입이 const char (buff &) [3]가 아닌 const char * (올바르게 이해한다면)입니까?

#include <iostream> 

template <class T> 
void f(T buff) { 
    std::cout << "f:buff size:" << sizeof(buff) << std::endl;  //prints 4 
} 

template <class T> 
void f1(T& buff) { 
    std::cout << "f:buff size:" << sizeof(buff) << std::endl;  //prints 3 
} 

int main(int argc, char *argv[]) { 
    const char buff[3] = {0,0,0}; 
    std::cout << "buff size:" << sizeof(buff) << std::endl;   //prints 3 
    f(buff); 
    f1(buff); 
    return 0; 
} 
+0

간단히 'in t '를'f'로하면'T'는'int'가 아니라'int'가됩니다. 그러므로, "왜 함수의 형태가 const char [3]이 아니라"const char *'입니까?와 같은 질문을해야합니다. " (누락 된 '&'귀하의 답변에 비해) –

+0

... (내 마지막 코멘트에서 계속). C/C++ 언어에 대한 가장 바보 같은 점은 매개 변수에'const char [3]'을 넣으면 컴파일러는 그것을 자동적으로'const char *'로 재 작성한다는 것입니다. 예를 들어, 로컬 변수에서는 이와 같은 일이 발생하지 않습니다. 나는 이것이 현재 (C++ 컴파일러에서 적어도) 경고로 이어져야한다고 생각한다. –

답변

7

배열을 함수 매개 변수로 전달할 수 없기 때문에.
값으로 전달하면 포인터로 감소합니다. 이 함수에서

:

template <class T> 
void f(T buff) { 

T 등이 char (&buff)[3] 수 없다는 기준이다. 컴파일러는 char (buff)[3]을 값으로 전달하려고했으나 허용되지 않았습니다. 그래서 그것을 작동시키기 위해 포인터를 붕괴시켜야합니다. 여기에 배열이 참조로 전달되기 때문에

두 번째 기능이 작동 : 함수 인수로 배열을 가질 수 없습니다

template <class T> 
void f1(T& buff) { 

// Here T& => char (&buff)[3] 
+0

나는 값으로 전달할 수없는 이유는 복사/할당의 부족과 관련이 있다고 믿는다. (비록 그것이 모두 빠진 이유는 나를 넘어선 것이다.) –

+0

@MooingDuck : C++에서 그 이유는 C에서 상속 된 것이기 때문이다. C에서 이유는 달라질 것이다 ... –

+1

@MooingDuck : 물론 그 중 하나 다. 'std :: array <> '를 원시 C- 배열보다 즉각적으로 우월하게 만드는 것들에 대해 설명합니다. – ildjarn

1

때문입니다. 그들은 배열 참조를 가질 수 있습니다.

1

이유는 기본적으로 서로 다른 오버로드를 일치시킬 때 공제를 입력하는 것입니다. f을 호출하면 컴파일러에서 유형을 const char[3]으로 추론합니다. 은 다음과 같이 배열됩니다.은 배열이 입니다. 이것은 컴파일러가 int이 아니고 int&이 아니라고 추론하는 것과 동일한 방식으로 수행됩니다.

인수가 참조로 취해 졌기 때문에 f1의 경우 컴파일러는 T를 const char[3]으로 다시 추론하지만 참조가 필요합니다.

아무것도

0

f1()에서 ... 정말 놀라운하지만, 함수 인수로 사용할 때 포인터로 배열의 붕괴 아니었다면 오히려 일관성, 크기 4는 4 바이트 포인터의 크기입니다. 이 함수에는 배열에 대한 포인터가 있기 때문입니다.

f1()에는 참조 (또는 다른 이름)별로 배열이 있으며 실제 배열 크기입니다. P가 참조 형식이 아닌 경우

4

사양 인용하기 위해서는

(14.8.2.1/2) 메시지 : - A는 어레이 형의 배열에 의해 생성 된 포인터 타입, 이면 -pointer 표준 변환 (4.2)는 형식 공제를 위해 A 대신 사용됩니다. 그렇지 않으면

그래서, 귀하의 경우,

template <class T> 
void f1(T& buff) { 
    std::cout << "f:buff size:" << sizeof(buff) << std::endl;  //prints 3 
} 

포인터로 부패하지 않는 것이 분명하다.

5

배열은 기능에 값으로 을 전달할 수 없기 때문입니다. 그래서 그것을 작동시키기 위해서, 배열은 포인터로 붕괴되고, 함수 에 값으로 전달됩니다. 환언

이 값에 의해 배열을 전달하는 것은 다른 배열로 배열 초기화 유사하지만 ++ C에 배열다른 배열을 초기화 할 수 그렇다면

char buff[3] = {0,0,0}; 
char x[3] = buff; //error 

배열이 =의 오른쪽에 나타나고, 왼쪽이 pointer 또는 reference 유형이어야합니다.

char *y = buff; //ok - pointer 
char (&z)[3] = buff; //ok - reference 

데모 : http://www.ideone.com/BlfSv

그것은 같은 이유로 auto에 대해 정확히 아래 각각의 경우에 다른 추론이다 (auto는 C++ (11)와 함께 제공주의) :

auto a = buff; //a is a pointer - a is same as y (above) 
std::cout << sizeof(a) << std::endl; //sizeof(a) == sizeof(char*) 

auto & b = buff; //b is a reference to the array - b is same as z (above) 
std::cout << sizeof(b) << std::endl; //sizeof(b) == sizeof(char[3]) 

출력 :

4 //size of the pointer 
3 //size of the array of 3 chars 

데모 : http://www.ideone.com/aXcF5