Recently I've been noticing "sizeof..." used with
parameter packs in templated code. For example:
template< class... Types >
class tuple_size< std::tuple<Types...> >
: public std::integral_constant<std::size_t, sizeof...(Types)> { };
The syntax struck me as a bit odd, and I wasn't sure how to parse it. I suppose I was thinking of the "..." as some kind of operator that was being applied to the usual
sizeof. Turns out that no, it's something different.
sizeof - Returns the byte size of a variable/expression or type
sizeof... - Returns the number of items in a parameter pack
It's special syntax that means something very specific. Even the parenthesis seem to be part of the syntax. If you try to omit the parenthesis, it's a compile error. With GCC, you can reduce the error to a warning with the flag "-fpermissive", but it still flags the code as bad.
The treatment of the parenthesis seemed in contrast to the usual
sizeof operator, where parenthesis are commonly used, though optional. Or so I thought. It turns out the parenthesis for regular
sizeof are only optional for expressions, but required for types.
// Use with variable/expression
int array[1];
std::cout << sizeof(array) << std::endl; // Ok: 4
std::cout << sizeof array << std::endl; // Ok: 4 (parenthesis optional)
// Use with type
std::cout << sizeof(int[1]) << std::endl; // Ok: 4
std::cout << sizeof int[1] << std::endl; // Syntax error
I should also emphasise that regular
sizeof returns the byte size, not the number of elements in an array. This is in constrast to
sizeof..., which returns the number of items in a parameter pack. It seems they are reusing the
sizeof keyword, for two concepts that aren't all that closely related, much like how
auto got repurposed.
Here's an example using parameter packs and
sizeof...:
#include <iostream>
template<typename... Types>
void printNumParams(Types... values) {
std::cout << sizeof...(Types) << std::endl; // Ok
//std::cout << sizeof... Types << std::endl; // Syntax Error/Warning
}
int main() {
printNumParams(1, 3.14); // 2
printNumParams(1, 3.14, "string"); // 3
}