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 deviationsCan I use a template to set array size?Why a compiler doesn't deduce the template parameter in case of zero array?
Is "montäglich" commonly used?
Does "solicit" mean the solicitor must receive what is being solicited in context of 52 U.S. Code Section 30121?
ASCII texturing
What is :>filename.txt Doing?
Why has no one requested the tape of the Trump/Ukraine call?
What tense is used in "Tomorrow I die"?
Can the fact that Trump issued a Do Not Testify be used in impeachment articles?
Is it a mistake to use a password that has previously been used (by anyone ever)?
Can the treble clef be used instead of the bass clef in piano music?
Two button calculator part 2
Stack data structure in python 3
Can I use pavers as a cheap solution to stop rain water erosion?
Why would prey creatures not hate predator creatures?
Looking for a reference in Greek
Did Ohio pass a law granting students the right to give scientifically wrong answers consistent with their religious beliefs?
What latex template to use when you do not know the journal you are going to submit
Days in indexed month
Should I tell an editor that I believe an article I'm reviewing is not good enough for the journal?
What are the minimum element requirements for a star?
How can I add an ammeter and/or voltmeter to my home breaker panel?
Ethics: Is it ethical for a professor to conduct research using a student's ideas without giving them credit?
What is the "two-drive trick" that can read Amiga disks on a PC?
Reliable temperature/humidity logging with Python and a DHT11
What does this docker log entry mean?
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 deviationsCan 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;
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++
add a comment
|
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++
Did you read something like n3337 about C++11 ? It should be relevant to your question ! Did you consider usingstd::array
orstd::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
add a comment
|
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++
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++
c++ visual-c++
edited Oct 17 at 2:07
John Kugelman supports Monica
269k59 gold badges432 silver badges482 bronze badges
269k59 gold badges432 silver badges482 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 usingstd::array
orstd::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
add a comment
|
Did you read something like n3337 about C++11 ? It should be relevant to your question ! Did you consider usingstd::array
orstd::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
add a comment
|
2 Answers
2
active
oldest
votes
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
char
s. 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.
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.
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
|
show 7 more comments
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.
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 havestd::extent
since C++11 which is compile time.
– L. F.
Oct 17 at 9:25
add a comment
|
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
char
s. 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.
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.
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
|
show 7 more comments
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
char
s. 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.
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.
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
|
show 7 more comments
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
char
s. 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.
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.
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
char
s. 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.
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.
edited Oct 17 at 6:09
answered Oct 16 at 8:03
BoBTFishBoBTFish
16.6k2 gold badges40 silver badges65 bronze badges
16.6k2 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
|
show 7 more comments
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
|
show 7 more comments
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.
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 havestd::extent
since C++11 which is compile time.
– L. F.
Oct 17 at 9:25
add a comment
|
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.
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 havestd::extent
since C++11 which is compile time.
– L. F.
Oct 17 at 9:25
add a comment
|
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.
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.
edited Oct 16 at 8:06
answered Oct 16 at 7:54
bolovbolov
43.4k11 gold badges89 silver badges156 bronze badges
43.4k11 gold badges89 silver badges156 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 havestd::extent
since C++11 which is compile time.
– L. F.
Oct 17 at 9:25
add a comment
|
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 havestd::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
add a comment
|
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
Did you read something like n3337 about C++11 ? It should be relevant to your question ! Did you consider using
std::array
orstd::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