이 템플릿 코드는 배열의 크기를 어떻게 얻습니까?


61

왜 이런 종류의 코드가 테스트 배열의 크기를 얻을 수 있는지 궁금합니다. 템플릿의 문법에 익숙하지 않습니다. 누군가가 아래 코드의 의미를 설명 할 수 template<typename,size_t>있습니다. 게다가, 참조 링크도 선호됩니다.

#define dimof(array) (sizeof(DimofSizeHelper(array)))
template <typename T, size_t N>
char(&DimofSizeHelper(T(&array)[N]))[N];

void InitDynCalls()
{
    char test[20];
    size_t n = dimof(test);
    printf("%d", n);
}

C ++ 11 에 대해 n3337 과 같은 것을 읽었습니까 ? 질문과 관련이 있어야합니다! 당신은 사용을 고려 했 나 ...std::arraystd::vector
실레 Starynkevitch

@BasileStarynkevitch 나는 그것을 읽지 못했습니다. 코드는 타사 라이브러리에 나타납니다. 나는 그 의미를 이해하고 싶다.
Shadow fiend

유용한 정보를 얻으려면 norvig.com/21-days.html 을 참조하십시오 (그리고 해당 페이지의 저자는 누구인지 확인하십시오).
Basile Starynkevitch


@BasileStarynkevitch 나는 그 링크의 관련성을 이해하지 못한다.
궤도에서 가벼움 경주

답변:


86

이것은 실제로 설명하기가 매우 어렵지만, 나는 그것을 갈 것입니다 ...

먼저 배열 dimof차원 또는 요소 수를 알려줍니다 . ( "차원"은 Windows 프로그래밍 환경에서 선호되는 용어라고 생각합니다).

때문에 필요 C++하고 C당신에게 배열의 크기를 결정하는 기본 방법을 제공하지 않습니다.


종종 사람들은 효과 sizeof(myArray)가 있다고 생각 하지만 실제로는 요소 수보다는 메모리 크기를 제공합니다. 각 요소는 아마도 1 바이트 이상의 메모리를 필요로합니다!

다음으로 시도해 볼 수 있습니다 sizeof(myArray) / sizeof(myArray[0]). 이것은 배열의 메모리의 크기를 첫 번째 요소의 크기로 나눈 것입니다. 괜찮고 C코드 에서 널리 사용됩니다 . 이것의 주요 문제는 배열 대신 포인터를 전달하면 작동하는 것처럼 보입니다. 메모리에서 포인터의 크기는 일반적으로 4 또는 8 바이트이지만, 1000의 요소로 구성된 배열 일 수도 있습니다.


따라서 다음으로 시도해야 할 것은 C++템플릿을 사용하여 배열에서만 작동하는 것을 강제하고 포인터에 컴파일러 오류를 발생시키는 것입니다. 다음과 같이 보입니다 :

template <typename T, std::size_t N>
std::size_t ArraySize(T (&inputArray)[N])
{
    return N;
}
//...
float x[7];
cout << ArraySize(x); // prints "7"

템플릿은 배열에서만 작동합니다. 유형 (실제로 필요하지는 않지만 템플릿이 작동하도록해야 함)과 배열의 크기를 추론 한 다음 크기를 반환합니다. 템플릿을 작성하는 방법은 포인터로 작동 할 수 없습니다.

일반적으로 여기서 멈출 수 있으며 이것은 C ++ 표준 라이브러리에 있습니다 std::size.


경고 : 여기 아래는 털이 많은 언어 변호사 영역에 들어갑니다.


이것은 꽤 멋지지만, 모호한 경우에는 여전히 실패합니다.

struct Placeholder {
    static float x[8];
};

template <typename T, int N>
int ArraySize (T (&)[N])
{
    return N;
}

int main()
{
    return ArraySize(Placeholder::x);
}

배열 x선언 되었지만 정의 되지 않았습니다 . 함수 (즉, 호출하려면 ArraySize그것을) x해야 정의 .

In function `main':
SO.cpp:(.text+0x5): undefined reference to `Placeholder::x'
collect2: error: ld returned 1 exit status

이걸 연결할 수 없습니다.


질문에있는 코드는 그 주위에 방법입니다. 실제로 함수를 호출하는 대신 정확한 크기의 객체반환하는 함수를 선언합니다 . 그런 다음 그 sizeof트릭을 사용합니다 .

그것은 보이는 우리가 함수를 호출처럼,하지만 sizeof기능은 결코 실제로 호출되는, 그래서 순수하게 컴파일 시간 구조입니다.

template <typename T, size_t N>
char(&DimofSizeHelper(T(&array)[N]))[N];
^^^^ ^                               ^^^
// a function that returns a reference to array of N chars - the size of this array in memory will be exactly N bytes

실제로 함수에서 배열을 반환 할 수는 없지만 배열에 대한 참조를 반환 할 수 있습니다.

이어서 DimofSizeHelper(myArray)표현종류 에 배열 N char들. 표현식을 실제로 실행할 필요는 없지만 컴파일 타임에 의미가 있습니다.

따라서 실제로 함수를 호출하면 얻을 수있는 것의 컴파일 타임크기를sizeof(DimofSizeHelper(myArray)) 알려줍니다 . 실제로 전화하지는 않지만.

오스틴 파워 크로스 아이드


마지막 블록이 이해가되지 않더라도 걱정하지 마십시오. 기괴한 가장자리 사건을 해결하는 것은 기묘한 트릭입니다. 그렇기 때문에 이런 종류의 코드를 직접 작성하지 말고 라이브러리 구현자가 이러한 종류의 말도 안되는 것에 대해 걱정하게하십시오.


3
@Shadowfiend 또한 잘못되었습니다. 실제로 함수의 선언이 아니기 때문에 함수 참조의 선언이기 때문에 그보다 더 추악한 일이 있습니다.
BoBTFish

5
왜 함수 참조의 선언입니까? "DimofSizeHelper"앞의 "&"는 반환 유형이 char (&) [N]이며 bolov의 답변에 따라 다릅니다.
Shadow fiend

3
@Shadowfiend 물론입니다. 나는 뇌가 매듭에 묶여서 쓰레기를 말하고있었습니다.
BoBTFish

차원은 배열의 요소 수가 아닙니다. 즉, 1, 2, 3 또는 그 이상의 차원 배열이있을 수 있으며 각각 같은 수의 요소를 가질 수 있습니다. 예를 들어 array1D [1000], array 2D [10] [100], array3D [10] [10] [10]. 각각 1000 개의 요소가 있습니다.
jamesqf 2009 년

1
@jamesqf C ++과 같은 언어에서 다차원 배열은 단순히 다른 배열을 포함하는 배열입니다. 컴파일러의 관점에서 보면 기본 배열의 요소 수는 내용과 완전히 관련이없는 경우가 많습니다 (2 차 또는 3 차 배열 일 수 있음).
Phlarx

27
template <typename T, size_t N>
char(&DimofSizeHelper(T(&array)[N]))[N];

// see it like this:
//                char(&DimofSizeHelper(T(&array)[N]))[N];
// template name:       DimofSizeHelper
// param name:                             array
// param type:                          T(&     )[N])
// return type:   char(&                             )[N];

DimofSizeHelperT(&)[N]매개 변수 를 사용하는 템플릿 함수입니다. 즉, 형식이 N 인 요소의 C- 어레이에 대한 참조를 가져 T오고 char (&)[N]N 문자 배열에 대한 참조를 일명 반환합니다 . C ++에서 문자는 변장 바이트이며 표준에 의해 sizeof(char)보장됩니다 1.

size_t n = dimof(test);
// macro expansion:
size_t n = sizeof(DimofSizeHelper(array));

n의 리턴 타입의 크기를 할당 DimofSizeHelper하고, sizeof(char[N])인을 N.


이것은 조금 복잡합니다 그리고 불필요. 일반적인 방법은 다음과 같습니다.

template <class T, size_t N>
/*constexpr*/ size_t sizeof_array(T (&)[N]) { return N; }

C ++ 17부터는 이것이 필요하기 때문에 불필요 std::size하지만 더 일반적인 방식으로 stl 스타일 컨테이너의 크기를 얻을 수 있습니다.


BoBTFish가 지적한 바와 같이, 엣지 케이스가 필요합니다.


2
ODR을 사용할 수없는 경우 크기를 사용하려는 배열을 선언해야합니다 (선언되었지만 정의되지 않음). 분명히, 꽤 모호합니다.
BoBTFish

템플릿 함수에서 유형을 설명해 주셔서 감사합니다. 정말 도움이됩니다.
Shadow fiend

3
우리 std::extent는 컴파일 시간 인 C ++ 11부터 가지고 있습니다 .
LF
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.