Author Topic: Sizeof versus sizeof...  (Read 3327 times)

Offline Hooman

  • Administrator
  • Hero Member
  • *****
  • Posts: 4954
Sizeof versus sizeof...
« on: December 04, 2018, 01:22:14 AM »
Recently I've been noticing "sizeof..." used with parameter packs in templated code. For example:
Code: cpp [Select]

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.
Code: cpp [Select]

  // 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...:
Code: cpp [Select]

#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