How does this template code to get the size of an array work?What does it mean to “ODR-use” something?How does “sizeof” work in this helper for determining array size?How does delete[] “know” the size of the operand array?How can I profile C++ code running on Linux?What does the C++ standard state the size of int, long type to be?How does the compilation/linking process work?C++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?Print template typename at compile timeReplacing a 32-bit loop counter with 64-bit introduces crazy performance deviations with _mm_popcnt_u64 on Intel CPUsCan I use a template to set array size?Why a compiler doesn't deduce the template parameter in case of zero array?

I forgot to validate my student visa in France. Can I leave?

Do asylum seekers in the Netherlands need fifteen family members in the country?

Fixing the fields in an incorrectly generated file

Running DOS, Windows 3, and Windows 98 from one FAT32 partition?

Is it possible for a moon to have a higher surface gravity than the planet it is attached to?

Could a planet have a single source of wind?

Relinquishing Green card at CA/Mexico border

How to move directory into a directory with the same name?

Should user input be validated for its length in PHP (server side) as a security measure?

If I drop a bag of of say 15 alchemist fire on giant and hits it will it take 15d4 of fire damage and so on?

How could pirates reasonably transport dinosaurs in captivity, some of them enormous, across oceans?

Best spot within a human to place redundant heart

Conditional types in Typescript

How to educate bachelor and master exchange students from Asia?

Is this platform game level winnable?

What is the meaning of "wiped my face with a planet"?

How to salvage money from a call option that has lost value?

Microtype expansion gets disabled when fontsize is changed! (lualatex)

Why use "con que" instead of just "que"?

What does "a flight to quality" mean?

Did Roger Rabbit exist prior to the film "Who Framed Roger Rabbit?"

Why "alle Tale" and not "alle Täler"?

Why is the 'anti' in 'anti-semitism'?

Can a German employer force mandatory overtime and forbid salary discussion?



How does this template code to get the size of an array work?


What does it mean to “ODR-use” something?How does “sizeof” work in this helper for determining array size?How does delete[] “know” the size of the operand array?How can I profile C++ code running on Linux?What does the C++ standard state the size of int, long type to be?How does the compilation/linking process work?C++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?Print template typename at compile timeReplacing a 32-bit loop counter with 64-bit introduces crazy performance deviations with _mm_popcnt_u64 on Intel CPUsCan I use a template to set array size?Why a compiler doesn't deduce the template parameter in case of zero array?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;









61


















I wonder why this kind of code can get the size of the test array? I'm not familiar with the grammar in template. Maybe someone could explain the meaning of the code under template<typename,size_t>. Besides, a reference link is preferred too.



#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);











share|improve this question



























  • Did you read something like n3337 about C++11 ? It should be relevant to your question ! Did you consider using std::array or std::vector ....

    – Basile Starynkevitch
    Oct 16 at 8:13












  • @BasileStarynkevitch I have not read that. The code appears in a third-party library. I just want to figure out the meaning.

    – Shadow fiend
    Oct 16 at 8:25











  • See also norvig.com/21-days.html for a useful insight (and look who is the author of that page).

    – Basile Starynkevitch
    Oct 16 at 8:39






  • 2





    Looks like a duplicate of stackoverflow.com/questions/6106158/…

    – sharptooth
    Oct 17 at 12:23











  • @BasileStarynkevitch I don't understand the relevance of that link.

    – Lightness Races with Monica
    Oct 17 at 17:36

















61


















I wonder why this kind of code can get the size of the test array? I'm not familiar with the grammar in template. Maybe someone could explain the meaning of the code under template<typename,size_t>. Besides, a reference link is preferred too.



#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);











share|improve this question



























  • Did you read something like n3337 about C++11 ? It should be relevant to your question ! Did you consider using std::array or std::vector ....

    – Basile Starynkevitch
    Oct 16 at 8:13












  • @BasileStarynkevitch I have not read that. The code appears in a third-party library. I just want to figure out the meaning.

    – Shadow fiend
    Oct 16 at 8:25











  • See also norvig.com/21-days.html for a useful insight (and look who is the author of that page).

    – Basile Starynkevitch
    Oct 16 at 8:39






  • 2





    Looks like a duplicate of stackoverflow.com/questions/6106158/…

    – sharptooth
    Oct 17 at 12:23











  • @BasileStarynkevitch I don't understand the relevance of that link.

    – Lightness Races with Monica
    Oct 17 at 17:36













61













61









61


12






I wonder why this kind of code can get the size of the test array? I'm not familiar with the grammar in template. Maybe someone could explain the meaning of the code under template<typename,size_t>. Besides, a reference link is preferred too.



#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);











share|improve this question
















I wonder why this kind of code can get the size of the test array? I'm not familiar with the grammar in template. Maybe someone could explain the meaning of the code under template<typename,size_t>. Besides, a reference link is preferred too.



#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++ visual-c++






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Oct 17 at 2:07









John Kugelman supports Monica

270k59 gold badges432 silver badges483 bronze badges




270k59 gold badges432 silver badges483 bronze badges










asked Oct 16 at 7:31









Shadow fiendShadow fiend

6034 silver badges7 bronze badges




6034 silver badges7 bronze badges















  • Did you read something like n3337 about C++11 ? It should be relevant to your question ! Did you consider using std::array or std::vector ....

    – Basile Starynkevitch
    Oct 16 at 8:13












  • @BasileStarynkevitch I have not read that. The code appears in a third-party library. I just want to figure out the meaning.

    – Shadow fiend
    Oct 16 at 8:25











  • See also norvig.com/21-days.html for a useful insight (and look who is the author of that page).

    – Basile Starynkevitch
    Oct 16 at 8:39






  • 2





    Looks like a duplicate of stackoverflow.com/questions/6106158/…

    – sharptooth
    Oct 17 at 12:23











  • @BasileStarynkevitch I don't understand the relevance of that link.

    – Lightness Races with Monica
    Oct 17 at 17:36

















  • Did you read something like n3337 about C++11 ? It should be relevant to your question ! Did you consider using std::array or std::vector ....

    – Basile Starynkevitch
    Oct 16 at 8:13












  • @BasileStarynkevitch I have not read that. The code appears in a third-party library. I just want to figure out the meaning.

    – Shadow fiend
    Oct 16 at 8:25











  • See also norvig.com/21-days.html for a useful insight (and look who is the author of that page).

    – Basile Starynkevitch
    Oct 16 at 8:39






  • 2





    Looks like a duplicate of stackoverflow.com/questions/6106158/…

    – sharptooth
    Oct 17 at 12:23











  • @BasileStarynkevitch I don't understand the relevance of that link.

    – Lightness Races with Monica
    Oct 17 at 17:36
















Did you read something like n3337 about C++11 ? It should be relevant to your question ! Did you consider using std::array or std::vector ....

– Basile Starynkevitch
Oct 16 at 8:13






Did you read something like n3337 about C++11 ? It should be relevant to your question ! Did you consider using std::array or std::vector ....

– Basile Starynkevitch
Oct 16 at 8:13














@BasileStarynkevitch I have not read that. The code appears in a third-party library. I just want to figure out the meaning.

– Shadow fiend
Oct 16 at 8:25





@BasileStarynkevitch I have not read that. The code appears in a third-party library. I just want to figure out the meaning.

– Shadow fiend
Oct 16 at 8:25













See also norvig.com/21-days.html for a useful insight (and look who is the author of that page).

– Basile Starynkevitch
Oct 16 at 8:39





See also norvig.com/21-days.html for a useful insight (and look who is the author of that page).

– Basile Starynkevitch
Oct 16 at 8:39




2




2





Looks like a duplicate of stackoverflow.com/questions/6106158/…

– sharptooth
Oct 17 at 12:23





Looks like a duplicate of stackoverflow.com/questions/6106158/…

– sharptooth
Oct 17 at 12:23













@BasileStarynkevitch I don't understand the relevance of that link.

– Lightness Races with Monica
Oct 17 at 17:36





@BasileStarynkevitch I don't understand the relevance of that link.

– Lightness Races with Monica
Oct 17 at 17:36












2 Answers
2






active

oldest

votes


















86



















This is actually a really tough one to explain, but I'll give it a go...



Firstly, dimof tells you the dimension, or number of elements in an array. (I believe "dimension" is the preferred terminology in Windows programming environments).



This is necessary because C++ and C don't give you a native way to determine the size of an array.




Often people assume sizeof(myArray) will work, but that will actually give you the size in memory, rather than the number of elements. Each element probably takes more than 1 byte of memory!



Next, they might try sizeof(myArray) / sizeof(myArray[0]). This would give the size in memory of the array, divided by the size of the first element. It's ok, and widely used in C code. The major problem with this is that it will appear to work if you pass a pointer instead of an array. The size of a pointer in memory will usually be 4 or 8 bytes, even though the thing it points to might be an array of 1000s of elements.




So the next thing to try in C++ is to use templates to force something that only works for arrays, and will give a compiler error on a pointer. It looks like this:



template <typename T, std::size_t N>
std::size_t ArraySize(T (&inputArray)[N])

return N;

//...
float x[7];
cout << ArraySize(x); // prints "7"


The template will only work with an array. It will deduce the type (not really needed, but has to be there to get the template to work) and the size of the array, then it returns the size. The way the template is written cannot possibly work with a pointer.



Usually you can stop here, and this is in the C++ Standard Libary as std::size.




Warning: below here it gets into hairy language-lawyer territory.




This is pretty cool, but still fails in an obscure edge case:



struct Placeholder 
static float x[8];
;

template <typename T, int N>
int ArraySize (T (&)[N])

return N;


int main()

return ArraySize(Placeholder::x);



Note that the array x is declared, but not defined. To call a function (i.e. ArraySize) with it, x must be defined.



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


You can't link this.




The code you have in the question is a way around that. Instead of actually calling a function, we declare a function that returns an object of exactly the right size. Then we use the sizeof trick on that.



It looks like we call the function, but sizeof is purely a compile time construct, so the function never actually gets called.



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


Note you can't actually return an array from a function, but you can return a reference to an array.



Then DimofSizeHelper(myArray) is an expression whose type is an array on N chars. The expression doesn't actually have to be runable, but it makes sense at compile time.



Therefore sizeof(DimofSizeHelper(myArray)) will tell you the size at compile time of what you would get if you did actually call the function. Even though we don't actually call it.



Austin Powers Cross-Eyed




Don't worry if that last block didn't make any sense. It's a bizarre trick to work around a bizarre edge case. This is why you don't write this sort of code yourself, and let library implementers worry about this sort of nonsense.






share|improve this answer






















  • 3





    @Shadowfiend It's also wrong. Things are even uglier than that, because it's not actually a declaration of a function, it's a declaration of a function reference... I'm still figuring out how to possibly explain that.

    – BoBTFish
    Oct 16 at 8:13






  • 5





    Why it's a declaration of a function reference? The "&" before "DimofSizeHelper" means the return type is char(&)[N], accoring to bolov's answer.

    – Shadow fiend
    Oct 16 at 8:32






  • 3





    @Shadowfiend Absolutely right. I was just talking rubbish because I got my brain tied in a knot.

    – BoBTFish
    Oct 16 at 8:36











  • Dimension is not the number of elements in an array. That is, you might have 1, 2, 3, or higher dimensioned arrays, which could each have the same number of elements. E.g. array1D [1000], array 2D [10][100], array3D [10][10][10]. each having 1000 elements.

    – jamesqf
    Oct 16 at 19:25






  • 1





    @jamesqf In languages like C++, a multidimensional array is simply an array which contains other arrays. From the compiler's point of view, the number of elements in the primary array is often completely unrelated to its contents -- which may be secondary or tertiary arrays.

    – Phlarx
    Oct 16 at 21:26



















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];



DimofSizeHelper is a template function which takes a T(&)[N] parameter - aka a reference to a C-array of N elements of type T and returns a char (&)[N] aka a reference to an array of N chars. In C++ a char is byte in disguise and sizeof(char) is guaranteed to be 1 by the standard.



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


n is assigned the size of the return type of DimofSizeHelper, which is sizeof(char[N]) which is N.




This is a bit convoluted and unnecessary. The usual way to do it was:



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


Since C++17 this also is unnecessary, as we have std::size which does this, but in a more generic way, being able to get the size of any stl-style container.




As pointed out by BoBTFish, it is necessary for an edge case.






share|improve this answer






















  • 2





    It's necessary if you can't ODR-use the array you want to take the size of (it is declared but not defined). Admittedly, pretty obscure.

    – BoBTFish
    Oct 16 at 8:04











  • Thanks for having explaining the type in the template function. That really helps.

    – Shadow fiend
    Oct 16 at 8:10






  • 3





    We have std::extent since C++11 which is compile time.

    – L. F.
    Oct 17 at 9:25













Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);














draft saved

draft discarded
















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f58408024%2fhow-does-this-template-code-to-get-the-size-of-an-array-work%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown


























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









86



















This is actually a really tough one to explain, but I'll give it a go...



Firstly, dimof tells you the dimension, or number of elements in an array. (I believe "dimension" is the preferred terminology in Windows programming environments).



This is necessary because C++ and C don't give you a native way to determine the size of an array.




Often people assume sizeof(myArray) will work, but that will actually give you the size in memory, rather than the number of elements. Each element probably takes more than 1 byte of memory!



Next, they might try sizeof(myArray) / sizeof(myArray[0]). This would give the size in memory of the array, divided by the size of the first element. It's ok, and widely used in C code. The major problem with this is that it will appear to work if you pass a pointer instead of an array. The size of a pointer in memory will usually be 4 or 8 bytes, even though the thing it points to might be an array of 1000s of elements.




So the next thing to try in C++ is to use templates to force something that only works for arrays, and will give a compiler error on a pointer. It looks like this:



template <typename T, std::size_t N>
std::size_t ArraySize(T (&inputArray)[N])

return N;

//...
float x[7];
cout << ArraySize(x); // prints "7"


The template will only work with an array. It will deduce the type (not really needed, but has to be there to get the template to work) and the size of the array, then it returns the size. The way the template is written cannot possibly work with a pointer.



Usually you can stop here, and this is in the C++ Standard Libary as std::size.




Warning: below here it gets into hairy language-lawyer territory.




This is pretty cool, but still fails in an obscure edge case:



struct Placeholder 
static float x[8];
;

template <typename T, int N>
int ArraySize (T (&)[N])

return N;


int main()

return ArraySize(Placeholder::x);



Note that the array x is declared, but not defined. To call a function (i.e. ArraySize) with it, x must be defined.



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


You can't link this.




The code you have in the question is a way around that. Instead of actually calling a function, we declare a function that returns an object of exactly the right size. Then we use the sizeof trick on that.



It looks like we call the function, but sizeof is purely a compile time construct, so the function never actually gets called.



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


Note you can't actually return an array from a function, but you can return a reference to an array.



Then DimofSizeHelper(myArray) is an expression whose type is an array on N chars. The expression doesn't actually have to be runable, but it makes sense at compile time.



Therefore sizeof(DimofSizeHelper(myArray)) will tell you the size at compile time of what you would get if you did actually call the function. Even though we don't actually call it.



Austin Powers Cross-Eyed




Don't worry if that last block didn't make any sense. It's a bizarre trick to work around a bizarre edge case. This is why you don't write this sort of code yourself, and let library implementers worry about this sort of nonsense.






share|improve this answer






















  • 3





    @Shadowfiend It's also wrong. Things are even uglier than that, because it's not actually a declaration of a function, it's a declaration of a function reference... I'm still figuring out how to possibly explain that.

    – BoBTFish
    Oct 16 at 8:13






  • 5





    Why it's a declaration of a function reference? The "&" before "DimofSizeHelper" means the return type is char(&)[N], accoring to bolov's answer.

    – Shadow fiend
    Oct 16 at 8:32






  • 3





    @Shadowfiend Absolutely right. I was just talking rubbish because I got my brain tied in a knot.

    – BoBTFish
    Oct 16 at 8:36











  • Dimension is not the number of elements in an array. That is, you might have 1, 2, 3, or higher dimensioned arrays, which could each have the same number of elements. E.g. array1D [1000], array 2D [10][100], array3D [10][10][10]. each having 1000 elements.

    – jamesqf
    Oct 16 at 19:25






  • 1





    @jamesqf In languages like C++, a multidimensional array is simply an array which contains other arrays. From the compiler's point of view, the number of elements in the primary array is often completely unrelated to its contents -- which may be secondary or tertiary arrays.

    – Phlarx
    Oct 16 at 21:26
















86



















This is actually a really tough one to explain, but I'll give it a go...



Firstly, dimof tells you the dimension, or number of elements in an array. (I believe "dimension" is the preferred terminology in Windows programming environments).



This is necessary because C++ and C don't give you a native way to determine the size of an array.




Often people assume sizeof(myArray) will work, but that will actually give you the size in memory, rather than the number of elements. Each element probably takes more than 1 byte of memory!



Next, they might try sizeof(myArray) / sizeof(myArray[0]). This would give the size in memory of the array, divided by the size of the first element. It's ok, and widely used in C code. The major problem with this is that it will appear to work if you pass a pointer instead of an array. The size of a pointer in memory will usually be 4 or 8 bytes, even though the thing it points to might be an array of 1000s of elements.




So the next thing to try in C++ is to use templates to force something that only works for arrays, and will give a compiler error on a pointer. It looks like this:



template <typename T, std::size_t N>
std::size_t ArraySize(T (&inputArray)[N])

return N;

//...
float x[7];
cout << ArraySize(x); // prints "7"


The template will only work with an array. It will deduce the type (not really needed, but has to be there to get the template to work) and the size of the array, then it returns the size. The way the template is written cannot possibly work with a pointer.



Usually you can stop here, and this is in the C++ Standard Libary as std::size.




Warning: below here it gets into hairy language-lawyer territory.




This is pretty cool, but still fails in an obscure edge case:



struct Placeholder 
static float x[8];
;

template <typename T, int N>
int ArraySize (T (&)[N])

return N;


int main()

return ArraySize(Placeholder::x);



Note that the array x is declared, but not defined. To call a function (i.e. ArraySize) with it, x must be defined.



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


You can't link this.




The code you have in the question is a way around that. Instead of actually calling a function, we declare a function that returns an object of exactly the right size. Then we use the sizeof trick on that.



It looks like we call the function, but sizeof is purely a compile time construct, so the function never actually gets called.



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


Note you can't actually return an array from a function, but you can return a reference to an array.



Then DimofSizeHelper(myArray) is an expression whose type is an array on N chars. The expression doesn't actually have to be runable, but it makes sense at compile time.



Therefore sizeof(DimofSizeHelper(myArray)) will tell you the size at compile time of what you would get if you did actually call the function. Even though we don't actually call it.



Austin Powers Cross-Eyed




Don't worry if that last block didn't make any sense. It's a bizarre trick to work around a bizarre edge case. This is why you don't write this sort of code yourself, and let library implementers worry about this sort of nonsense.






share|improve this answer






















  • 3





    @Shadowfiend It's also wrong. Things are even uglier than that, because it's not actually a declaration of a function, it's a declaration of a function reference... I'm still figuring out how to possibly explain that.

    – BoBTFish
    Oct 16 at 8:13






  • 5





    Why it's a declaration of a function reference? The "&" before "DimofSizeHelper" means the return type is char(&)[N], accoring to bolov's answer.

    – Shadow fiend
    Oct 16 at 8:32






  • 3





    @Shadowfiend Absolutely right. I was just talking rubbish because I got my brain tied in a knot.

    – BoBTFish
    Oct 16 at 8:36











  • Dimension is not the number of elements in an array. That is, you might have 1, 2, 3, or higher dimensioned arrays, which could each have the same number of elements. E.g. array1D [1000], array 2D [10][100], array3D [10][10][10]. each having 1000 elements.

    – jamesqf
    Oct 16 at 19:25






  • 1





    @jamesqf In languages like C++, a multidimensional array is simply an array which contains other arrays. From the compiler's point of view, the number of elements in the primary array is often completely unrelated to its contents -- which may be secondary or tertiary arrays.

    – Phlarx
    Oct 16 at 21:26














86















86











86









This is actually a really tough one to explain, but I'll give it a go...



Firstly, dimof tells you the dimension, or number of elements in an array. (I believe "dimension" is the preferred terminology in Windows programming environments).



This is necessary because C++ and C don't give you a native way to determine the size of an array.




Often people assume sizeof(myArray) will work, but that will actually give you the size in memory, rather than the number of elements. Each element probably takes more than 1 byte of memory!



Next, they might try sizeof(myArray) / sizeof(myArray[0]). This would give the size in memory of the array, divided by the size of the first element. It's ok, and widely used in C code. The major problem with this is that it will appear to work if you pass a pointer instead of an array. The size of a pointer in memory will usually be 4 or 8 bytes, even though the thing it points to might be an array of 1000s of elements.




So the next thing to try in C++ is to use templates to force something that only works for arrays, and will give a compiler error on a pointer. It looks like this:



template <typename T, std::size_t N>
std::size_t ArraySize(T (&inputArray)[N])

return N;

//...
float x[7];
cout << ArraySize(x); // prints "7"


The template will only work with an array. It will deduce the type (not really needed, but has to be there to get the template to work) and the size of the array, then it returns the size. The way the template is written cannot possibly work with a pointer.



Usually you can stop here, and this is in the C++ Standard Libary as std::size.




Warning: below here it gets into hairy language-lawyer territory.




This is pretty cool, but still fails in an obscure edge case:



struct Placeholder 
static float x[8];
;

template <typename T, int N>
int ArraySize (T (&)[N])

return N;


int main()

return ArraySize(Placeholder::x);



Note that the array x is declared, but not defined. To call a function (i.e. ArraySize) with it, x must be defined.



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


You can't link this.




The code you have in the question is a way around that. Instead of actually calling a function, we declare a function that returns an object of exactly the right size. Then we use the sizeof trick on that.



It looks like we call the function, but sizeof is purely a compile time construct, so the function never actually gets called.



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


Note you can't actually return an array from a function, but you can return a reference to an array.



Then DimofSizeHelper(myArray) is an expression whose type is an array on N chars. The expression doesn't actually have to be runable, but it makes sense at compile time.



Therefore sizeof(DimofSizeHelper(myArray)) will tell you the size at compile time of what you would get if you did actually call the function. Even though we don't actually call it.



Austin Powers Cross-Eyed




Don't worry if that last block didn't make any sense. It's a bizarre trick to work around a bizarre edge case. This is why you don't write this sort of code yourself, and let library implementers worry about this sort of nonsense.






share|improve this answer
















This is actually a really tough one to explain, but I'll give it a go...



Firstly, dimof tells you the dimension, or number of elements in an array. (I believe "dimension" is the preferred terminology in Windows programming environments).



This is necessary because C++ and C don't give you a native way to determine the size of an array.




Often people assume sizeof(myArray) will work, but that will actually give you the size in memory, rather than the number of elements. Each element probably takes more than 1 byte of memory!



Next, they might try sizeof(myArray) / sizeof(myArray[0]). This would give the size in memory of the array, divided by the size of the first element. It's ok, and widely used in C code. The major problem with this is that it will appear to work if you pass a pointer instead of an array. The size of a pointer in memory will usually be 4 or 8 bytes, even though the thing it points to might be an array of 1000s of elements.




So the next thing to try in C++ is to use templates to force something that only works for arrays, and will give a compiler error on a pointer. It looks like this:



template <typename T, std::size_t N>
std::size_t ArraySize(T (&inputArray)[N])

return N;

//...
float x[7];
cout << ArraySize(x); // prints "7"


The template will only work with an array. It will deduce the type (not really needed, but has to be there to get the template to work) and the size of the array, then it returns the size. The way the template is written cannot possibly work with a pointer.



Usually you can stop here, and this is in the C++ Standard Libary as std::size.




Warning: below here it gets into hairy language-lawyer territory.




This is pretty cool, but still fails in an obscure edge case:



struct Placeholder 
static float x[8];
;

template <typename T, int N>
int ArraySize (T (&)[N])

return N;


int main()

return ArraySize(Placeholder::x);



Note that the array x is declared, but not defined. To call a function (i.e. ArraySize) with it, x must be defined.



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


You can't link this.




The code you have in the question is a way around that. Instead of actually calling a function, we declare a function that returns an object of exactly the right size. Then we use the sizeof trick on that.



It looks like we call the function, but sizeof is purely a compile time construct, so the function never actually gets called.



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


Note you can't actually return an array from a function, but you can return a reference to an array.



Then DimofSizeHelper(myArray) is an expression whose type is an array on N chars. The expression doesn't actually have to be runable, but it makes sense at compile time.



Therefore sizeof(DimofSizeHelper(myArray)) will tell you the size at compile time of what you would get if you did actually call the function. Even though we don't actually call it.



Austin Powers Cross-Eyed




Don't worry if that last block didn't make any sense. It's a bizarre trick to work around a bizarre edge case. This is why you don't write this sort of code yourself, and let library implementers worry about this sort of nonsense.







share|improve this answer















share|improve this answer




share|improve this answer








edited Oct 17 at 6:09

























answered Oct 16 at 8:03









BoBTFishBoBTFish

16.7k2 gold badges40 silver badges65 bronze badges




16.7k2 gold badges40 silver badges65 bronze badges










  • 3





    @Shadowfiend It's also wrong. Things are even uglier than that, because it's not actually a declaration of a function, it's a declaration of a function reference... I'm still figuring out how to possibly explain that.

    – BoBTFish
    Oct 16 at 8:13






  • 5





    Why it's a declaration of a function reference? The "&" before "DimofSizeHelper" means the return type is char(&)[N], accoring to bolov's answer.

    – Shadow fiend
    Oct 16 at 8:32






  • 3





    @Shadowfiend Absolutely right. I was just talking rubbish because I got my brain tied in a knot.

    – BoBTFish
    Oct 16 at 8:36











  • Dimension is not the number of elements in an array. That is, you might have 1, 2, 3, or higher dimensioned arrays, which could each have the same number of elements. E.g. array1D [1000], array 2D [10][100], array3D [10][10][10]. each having 1000 elements.

    – jamesqf
    Oct 16 at 19:25






  • 1





    @jamesqf In languages like C++, a multidimensional array is simply an array which contains other arrays. From the compiler's point of view, the number of elements in the primary array is often completely unrelated to its contents -- which may be secondary or tertiary arrays.

    – Phlarx
    Oct 16 at 21:26













  • 3





    @Shadowfiend It's also wrong. Things are even uglier than that, because it's not actually a declaration of a function, it's a declaration of a function reference... I'm still figuring out how to possibly explain that.

    – BoBTFish
    Oct 16 at 8:13






  • 5





    Why it's a declaration of a function reference? The "&" before "DimofSizeHelper" means the return type is char(&)[N], accoring to bolov's answer.

    – Shadow fiend
    Oct 16 at 8:32






  • 3





    @Shadowfiend Absolutely right. I was just talking rubbish because I got my brain tied in a knot.

    – BoBTFish
    Oct 16 at 8:36











  • Dimension is not the number of elements in an array. That is, you might have 1, 2, 3, or higher dimensioned arrays, which could each have the same number of elements. E.g. array1D [1000], array 2D [10][100], array3D [10][10][10]. each having 1000 elements.

    – jamesqf
    Oct 16 at 19:25






  • 1





    @jamesqf In languages like C++, a multidimensional array is simply an array which contains other arrays. From the compiler's point of view, the number of elements in the primary array is often completely unrelated to its contents -- which may be secondary or tertiary arrays.

    – Phlarx
    Oct 16 at 21:26








3




3





@Shadowfiend It's also wrong. Things are even uglier than that, because it's not actually a declaration of a function, it's a declaration of a function reference... I'm still figuring out how to possibly explain that.

– BoBTFish
Oct 16 at 8:13





@Shadowfiend It's also wrong. Things are even uglier than that, because it's not actually a declaration of a function, it's a declaration of a function reference... I'm still figuring out how to possibly explain that.

– BoBTFish
Oct 16 at 8:13




5




5





Why it's a declaration of a function reference? The "&" before "DimofSizeHelper" means the return type is char(&)[N], accoring to bolov's answer.

– Shadow fiend
Oct 16 at 8:32





Why it's a declaration of a function reference? The "&" before "DimofSizeHelper" means the return type is char(&)[N], accoring to bolov's answer.

– Shadow fiend
Oct 16 at 8:32




3




3





@Shadowfiend Absolutely right. I was just talking rubbish because I got my brain tied in a knot.

– BoBTFish
Oct 16 at 8:36





@Shadowfiend Absolutely right. I was just talking rubbish because I got my brain tied in a knot.

– BoBTFish
Oct 16 at 8:36













Dimension is not the number of elements in an array. That is, you might have 1, 2, 3, or higher dimensioned arrays, which could each have the same number of elements. E.g. array1D [1000], array 2D [10][100], array3D [10][10][10]. each having 1000 elements.

– jamesqf
Oct 16 at 19:25





Dimension is not the number of elements in an array. That is, you might have 1, 2, 3, or higher dimensioned arrays, which could each have the same number of elements. E.g. array1D [1000], array 2D [10][100], array3D [10][10][10]. each having 1000 elements.

– jamesqf
Oct 16 at 19:25




1




1





@jamesqf In languages like C++, a multidimensional array is simply an array which contains other arrays. From the compiler's point of view, the number of elements in the primary array is often completely unrelated to its contents -- which may be secondary or tertiary arrays.

– Phlarx
Oct 16 at 21:26






@jamesqf In languages like C++, a multidimensional array is simply an array which contains other arrays. From the compiler's point of view, the number of elements in the primary array is often completely unrelated to its contents -- which may be secondary or tertiary arrays.

– Phlarx
Oct 16 at 21:26














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];



DimofSizeHelper is a template function which takes a T(&)[N] parameter - aka a reference to a C-array of N elements of type T and returns a char (&)[N] aka a reference to an array of N chars. In C++ a char is byte in disguise and sizeof(char) is guaranteed to be 1 by the standard.



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


n is assigned the size of the return type of DimofSizeHelper, which is sizeof(char[N]) which is N.




This is a bit convoluted and unnecessary. The usual way to do it was:



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


Since C++17 this also is unnecessary, as we have std::size which does this, but in a more generic way, being able to get the size of any stl-style container.




As pointed out by BoBTFish, it is necessary for an edge case.






share|improve this answer






















  • 2





    It's necessary if you can't ODR-use the array you want to take the size of (it is declared but not defined). Admittedly, pretty obscure.

    – BoBTFish
    Oct 16 at 8:04











  • Thanks for having explaining the type in the template function. That really helps.

    – Shadow fiend
    Oct 16 at 8:10






  • 3





    We have std::extent since C++11 which is compile time.

    – L. F.
    Oct 17 at 9:25
















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];



DimofSizeHelper is a template function which takes a T(&)[N] parameter - aka a reference to a C-array of N elements of type T and returns a char (&)[N] aka a reference to an array of N chars. In C++ a char is byte in disguise and sizeof(char) is guaranteed to be 1 by the standard.



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


n is assigned the size of the return type of DimofSizeHelper, which is sizeof(char[N]) which is N.




This is a bit convoluted and unnecessary. The usual way to do it was:



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


Since C++17 this also is unnecessary, as we have std::size which does this, but in a more generic way, being able to get the size of any stl-style container.




As pointed out by BoBTFish, it is necessary for an edge case.






share|improve this answer






















  • 2





    It's necessary if you can't ODR-use the array you want to take the size of (it is declared but not defined). Admittedly, pretty obscure.

    – BoBTFish
    Oct 16 at 8:04











  • Thanks for having explaining the type in the template function. That really helps.

    – Shadow fiend
    Oct 16 at 8:10






  • 3





    We have std::extent since C++11 which is compile time.

    – L. F.
    Oct 17 at 9:25














27















27











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];



DimofSizeHelper is a template function which takes a T(&)[N] parameter - aka a reference to a C-array of N elements of type T and returns a char (&)[N] aka a reference to an array of N chars. In C++ a char is byte in disguise and sizeof(char) is guaranteed to be 1 by the standard.



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


n is assigned the size of the return type of DimofSizeHelper, which is sizeof(char[N]) which is N.




This is a bit convoluted and unnecessary. The usual way to do it was:



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


Since C++17 this also is unnecessary, as we have std::size which does this, but in a more generic way, being able to get the size of any stl-style container.




As pointed out by BoBTFish, it is necessary for an edge case.






share|improve this answer
















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];



DimofSizeHelper is a template function which takes a T(&)[N] parameter - aka a reference to a C-array of N elements of type T and returns a char (&)[N] aka a reference to an array of N chars. In C++ a char is byte in disguise and sizeof(char) is guaranteed to be 1 by the standard.



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


n is assigned the size of the return type of DimofSizeHelper, which is sizeof(char[N]) which is N.




This is a bit convoluted and unnecessary. The usual way to do it was:



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


Since C++17 this also is unnecessary, as we have std::size which does this, but in a more generic way, being able to get the size of any stl-style container.




As pointed out by BoBTFish, it is necessary for an edge case.







share|improve this answer















share|improve this answer




share|improve this answer








edited Oct 16 at 8:06

























answered Oct 16 at 7:54









bolovbolov

44.2k11 gold badges90 silver badges157 bronze badges




44.2k11 gold badges90 silver badges157 bronze badges










  • 2





    It's necessary if you can't ODR-use the array you want to take the size of (it is declared but not defined). Admittedly, pretty obscure.

    – BoBTFish
    Oct 16 at 8:04











  • Thanks for having explaining the type in the template function. That really helps.

    – Shadow fiend
    Oct 16 at 8:10






  • 3





    We have std::extent since C++11 which is compile time.

    – L. F.
    Oct 17 at 9:25













  • 2





    It's necessary if you can't ODR-use the array you want to take the size of (it is declared but not defined). Admittedly, pretty obscure.

    – BoBTFish
    Oct 16 at 8:04











  • Thanks for having explaining the type in the template function. That really helps.

    – Shadow fiend
    Oct 16 at 8:10






  • 3





    We have std::extent since C++11 which is compile time.

    – L. F.
    Oct 17 at 9:25








2




2





It's necessary if you can't ODR-use the array you want to take the size of (it is declared but not defined). Admittedly, pretty obscure.

– BoBTFish
Oct 16 at 8:04





It's necessary if you can't ODR-use the array you want to take the size of (it is declared but not defined). Admittedly, pretty obscure.

– BoBTFish
Oct 16 at 8:04













Thanks for having explaining the type in the template function. That really helps.

– Shadow fiend
Oct 16 at 8:10





Thanks for having explaining the type in the template function. That really helps.

– Shadow fiend
Oct 16 at 8:10




3




3





We have std::extent since C++11 which is compile time.

– L. F.
Oct 17 at 9:25






We have std::extent since C++11 which is compile time.

– L. F.
Oct 17 at 9:25



















draft saved

draft discarded















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f58408024%2fhow-does-this-template-code-to-get-the-size-of-an-array-work%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown









Popular posts from this blog

Invision Community Contents History See also References External links Navigation menuProprietaryinvisioncommunity.comIPS Community ForumsIPS Community Forumsthis blog entry"License Changes, IP.Board 3.4, and the Future""Interview -- Matt Mecham of Ibforums""CEO Invision Power Board, Matt Mecham Is a Liar, Thief!"IPB License Explanation 1.3, 1.3.1, 2.0, and 2.1ArchivedSecurity Fixes, Updates And Enhancements For IPB 1.3.1Archived"New Demo Accounts - Invision Power Services"the original"New Default Skin"the original"Invision Power Board 3.0.0 and Applications Released"the original"Archived copy"the original"Perpetual licenses being done away with""Release Notes - Invision Power Services""Introducing: IPS Community Suite 4!"Invision Community Release Notes

Canceling a color specificationRandomly assigning color to Graphics3D objects?Default color for Filling in Mathematica 9Coloring specific elements of sets with a prime modified order in an array plotHow to pick a color differing significantly from the colors already in a given color list?Detection of the text colorColor numbers based on their valueCan color schemes for use with ColorData include opacity specification?My dynamic color schemes

Ласкавець круглолистий Зміст Опис | Поширення | Галерея | Примітки | Посилання | Навігаційне меню58171138361-22960890446Bupleurum rotundifoliumEuro+Med PlantbasePlants of the World Online — Kew ScienceGermplasm Resources Information Network (GRIN)Ласкавецькн. VI : Літери Ком — Левиправивши або дописавши її