2012-06-28 4 views
-1

저는 C++ 함수 템플릿을 배우려고합니다. 배열을 함수 템플릿에 대한 포인터로 전달하고 있습니다. 그, 배열의 크기를 찾으려고 노력하고 있습니다. 다음은 내가 사용하는 함수 템플릿입니다.sizeof 연산자가 함수 템플릿 내에서 작동하지 않는 이유는 무엇입니까?

template<typename T> 
T* average(T *arr) 
{ 
    T *ansPtr,ans,sum = 0.0;  

    size_t sz = sizeof(arr)/sizeof(arr[0]); 
    cout<<"\nSz is "<<sz<<endl; 

    for(int i = 0;i < sz; i++) 
    { 
     sum = sum + arr[i]; 
    } 
    ans = (sum/sz); 
    ansPtr = &ans; 
    return ansPtr; 
} 

cout 문은 내가 5 정수 배열에 포인터를 전달하고 경우에도 arr1으로의 크기를 표시합니다. 이제는 이것이 제가 앞에서 언급 한 질문들의 가능한 중복일지도 모른다고 알고 있습니다 만 이것에 대해 더 나은 설명이 필요합니다. 내가 가지고 올 수

만 가지 템플릿이 런타임에 호출 및 sizeof은 컴파일 시간 연산자입니다 때문에이 편곡의 정확한 유형을 알고하지 않기 때문에, 컴파일러는 단지 라인

int sz = sizeof(arr)/sizeof(arr[0]); 

을 무시한다는 것입니다 실제로 함수를 호출 할 때까지 맞습니까? 아니면 여기에 놓친 것이 있습니까? 또한 함수 템플리트에 배열에 대한 포인터를 보내는 것이 신뢰할 수 있습니까?

+4

이것은 함수 템플릿과 아무 관련이 없습니다. 포인터를 취하는 일반 함수로 같은 것을 얻는다. 포인터가 배열이 아닙니다. – Mat

+0

가능한 [sizeof (배열을 가리키는 포인터)를 찾는 방법] (http://stackoverflow.com/questions/492384/how-to-find-the-sizeofa-pointer-pointing-to-an- 배열) –

+5

"템플릿은 런타임에 호출됩니다."잠깐, ** 무엇?! ** – ereOn

답변

6
T *arr 

이 "arrT에 대한 포인터입니다"에 대한 C++입니다. sizeof(arr) 분명히 이유는 "배열 arr"의 크기가 아니라 "포인터의 크기 arr"을 의미합니다. 그것이 그 계획의 중대한 결함입니다.

배열의 크기를 얻으려면 함수가 포인터를 사용하지 않고 배열에서 작동해야합니다. 모두가 아는 것처럼 (맞습니까?) 배열은 포인터가 아닙니다.

평균 함수는 평균값을 반환해야합니다. 그러나 T*은 "T에 대한 포인터"입니다. 평균 함수는 값에 대한 포인터를 반환하지 않아야합니다. 그것은 가치가 아닙니다.

포인터 반환 유형을 갖는 것은 마지막 위반이 아닙니다. 로컬 변수 에 대한 포인터를 반환하는 것은 모두 중 최악입니다. Why would you want to steal hotel room keys?

template<typename T, std::size_t sz> 
T average(T(&arr)[sz]) 
{ 
    T ans,sum = 0.0;  

    cout<<"\nSz is "<<sz<<endl; 

    for(int i = 0;i < sz; i++) 
    { 
     sum = sum + arr[i]; 
    } 
    ans = (sum/sz); 
    return ans; 
} 
+0

고맙습니다. 나는 평균 값의 포인터/참조를 반환하고 싶다고 언급 했어야합니다. 그러나 권장하지 않는 것으로 보입니다. 더 이상 배열을 전달하는 동안 T 평균 (T arr []) 을 사용해야 템플릿 함수 내부에서 크기를 찾을 수 있습니까? – Recker

+1

@abhinole'T average (T arr [])'및'T average (T * arr)'은 컴파일러와 완전히 동일합니다. –

+0

@abhinole 왜 포인터 또는 평균값에 대한 참조를 반환 하시겠습니까? * 평균값은 사전에 존재하지 않습니다 *. 이 함수에서 생성됩니다. 그것에 대한 포인터를 반환하는 것은 잘 작동하지 않을 것입니다. 값으로 반환하는 것이 가장 좋은 방법입니다. –

3

배열은 매개 변수로 전달 될 때 포인터로 쇠퇴하므로 효과적으로 포인터의 크기를 가져옵니다. 템플릿과는 아무런 관련이 없습니다. 언어가 어떻게 디자인 되었습니까.

4

당신이 전달 된 매개 변수의 크기를 액세스 할 수있게하려면 , 당신도 템플릿 매개 변수 있는지 확인해야 할 것 :

template<typename T, size_t Len> 
T average(const T (&arr)[Len]) 
{ 
    T sum = T(); 
    cout<<"\nSz is "<<Len<<endl; 
    for(int i = 0;i < Len; i++) 
    { 
     sum = sum + arr[i]; 
    } 
    return (sum/Len); 
} 

그런 다음 sizeof 연산자를 생략 할 수 있습니다, 명백하게. 그리고 실수로 동적으로 할당 된 배열을 파싱 할 수는 없습니다. 이는 좋은 일입니다. 단점은 템플릿이 모든 유형에 대해 한 번만 생성되는 것이 아니라 모든 크기에 대해 한 번 인스턴스화된다는 것입니다. 대량의 코드를 복사하지 않으려면 포인터와 길이를 받아들이고 평균을 반환하는 두 번째 템플릿 함수를 사용할 수 있습니다. 인라인 함수에서 호출 될 수 있습니다.

template<typename T> 
T average(const T* arr, size_t len) 
{ 
    T sum = T(); 
    cout<<"\nSz is "<<len<<endl; 
    for(int i = 0;i < len; i++) 
    { 
     sum = sum + arr[i]; 
    } 
    return (sum/len); 
} 

template<typename T, size_t Len> 
inline T average(const T (&arr)[Len]) 
{ 
    return average(arr, Len); 
} 

또한이 기능을보다 오래되지 않으므로 함수에 로컬 변수의 주소를 반환 할 경우는 매우 나쁜 생각 있습니다. 따라서 값을 반환하고 컴파일러가 불필요한 복사를 최적화하도록 처리하는 것이 좋습니다.

+1

평균화 할 대부분의 유형의 경우 사본은 포인터를 사용하는 것보다 저렴합니다. –

+1

평균 함수의 구현으로'accumulate (arr, arr + len, T())/len'을 사용할 수도 있습니다. [accumulate의 문서] (http://www.sgi.com/tech/stl/accumulate.html)를 참조하십시오. – MvG

1

다른 사람들은 즉각적인 오류를 지적했지만 IMHO에는 두 가지 중요한 점이 있습니다. 둘 다 은 생산 코드에서 오류가 있다고 생각합니다.

먼저 std::vector을 사용하지 않는 이유는 무엇입니까? 역사적인 이유로 C 스타일 배열이 손상되어 일반적으로 피해야합니다. 예외가 있지만 대부분 정적 변수 변수의 정적 초기화가 필요합니다. 결코은 C 유형의 배열을 함수 인수로 전달해야합니다. 사용자가 직면 한 문제가 발생하기 때문입니다. (이것은 템플릿 유형의 두 반복기 걸린다 그러나 효율적. 함수가 함수 템플릿되어야 배열 std::vector 모두 C 스타일 해결할 수있는 함수를 작성하는 것이 가능하다.)

번째 표준 라이브러리의 기능을 사용하지 않는 이유는 무엇입니까? 귀하의 기능은 기본적으로 한 줄에 쓸 수 있습니다 :

template <typename ForwardIterator> 
typename ForwardIterator::value_type 
average(ForwardIterator begin, ForwardIterator end) 
{ 
    return std::accumulate(begin, end, 
          typename::ForwardIterator::value_type()) 
       /std::distance(begin, end); 
} 

(이 기능은 물론, 소수점 형식 부동 신뢰할 수 없습니다, 어디 반올림 오류는 결과가 쓸모 수 있습니다 점 부동 전체적인 세트를 발생시킵니다. 오버 헤드가 발생할 위험이 있으므로 정수 유형에 대해서도 실제로는 은 신뢰할 수 없습니다. 그러나 이것들은 더 발전된 문제입니다.)

관련 문제