24

I was just wondering if there was anything in the C++0x std lib already available to count the number of parameters in a parameter pack? I'd like to get rid of the field_count in the code below. I know I can build my own counter, but it just seems like this would be an obvious thing to include in the C++0x std lib, and I wanted to be sure it wasn't already there :) Home-grown counter implementations are most welcome too.

template<const int field_count, typename... Args> struct Entity {
    const tuple<Args...> data;
    const array<const char*, field_count> source_names;

    Entity() : data() {
    }
};
James McNellis
  • 348,265
  • 75
  • 913
  • 977
Brett Rossier
  • 3,420
  • 3
  • 27
  • 36
  • 1
    Duplicate of [How to find the length of a parameter pack?](http://stackoverflow.com/questions/2770474/how-to-find-the-length-of-a-parameter-pack) I knew I had learned about `sizeof...` from an answer here... – James McNellis Sep 02 '10 at 19:28
  • I actually read that one before posting this question, but based on the cursory read I did, I wasn't sure they were getting at the actual number of parameters versus the total size of all parameters. Lol, I like my question better, it's clearer to me :) – Brett Rossier Sep 02 '10 at 20:56

2 Answers2

48

Yes, you can use sizeof.... From the C++0x FCD (§5.3.3/5):

The identifier in a sizeof... expression shall name a parameter pack. The sizeof... operator yields the number of arguments provided for the parameter pack identifier. The parameter pack is expanded (14.5.3) by the sizeof... operator. [Example:

template<class... Types>
struct count {
    static const std::size_t value = sizeof...(Types);
};

end example ]

Community
  • 1
  • 1
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • I like being able use sizeof this way, but now I'm curious/cautious. Typically I expect sizeof to return number of bytes, but here it unpacks and counts the args for me. With an array, the typical sizeof is going to give me the size in bytes of the array. Are there any "gotchas" people need to watch out for using sizeof...? I'm not expert enough w/ c++ to see at this point, but there's just something a little off to me about using sizeof to count things instead of getting their actual size in bytes. Am I just being semantically paranoid? lol. – Brett Rossier Sep 02 '10 at 16:50
  • 1
    @pheadbaq: You can only use `sizeof...` on a parameter pack and it always returns the number of arguments in the pack. I don't think there is much room for error in its use, but I see what you mean. Personally, I think `sizeof...` is a ridiculous abuse of the `sizeof` keyword, but, I don't write the language, I just use it. :-) – James McNellis Sep 02 '10 at 17:01
  • 14
    Note the difference of `sizeof...(Types)` and `sizeof(Types)...`. The latter is counting bytes, the former is counting types :) – Johannes Schaub - litb Sep 02 '10 at 23:26
  • @Johannes: In `sizeof(Types)...`, the parameter pack is expanded and `sizeof` is applied to each of the types in the parameter pack, right? How are the results of the multiple `sizeof` expressions combined? Are the sizes summed? 14.5.3/6 just says "the syntactically-appropriate separator for the list" is used. – James McNellis Sep 03 '10 at 19:08
  • @James of course it depends where it's unpacked. `f(sizeof(Types)...)` would unpack it into an `initializer-list` (assuming `f` is a function taking integers), and that syntactically-appropriate separator would be a `,` (comma). It doesn't produce a single integer :) In this case `sizeof(Types)` is a pattern, just like `f(Types()...)` would be the unpacking of a pattern resulting in a number of value constructed objects being passed. – Johannes Schaub - litb Sep 03 '10 at 20:13
  • @Johannes: Okay, that's kind of what I thought. I was just confused by your comment "the latter is counting bytes." I'm glad Visual C++ only has support for a few C++0x features. I'd hate to have to learn them all at once. – James McNellis Sep 03 '10 at 20:19
  • @James i was doing a littl pun -.- I'm sorry for teh confusion – Johannes Schaub - litb Sep 03 '10 at 20:20
  • @Johannes: No problem :-P I'm easily confused on Fridays. – James McNellis Sep 03 '10 at 20:24
7

Here's a link that may help you. Sample source from link:

template<typename... Args> struct count;

template<>
struct count<> {
    static const int value = 0;
};

template<typename T, typename... Args>
struct count<T, Args...> {
    static const int value = 1 + count<Args...>::value;
};
dirkgently
  • 108,024
  • 16
  • 131
  • 187
  • Link no longer works, why do you add 1 to the count? – Mark A. Ropper Jan 15 '18 at 13:25
  • It's a typical technique to count items in a list in functional languages, in which you can't increment a counter as everything is immutable, you create new variables/instances each 'iteration'. It is a recursive call, where one argument/type T, the first in the argument list, is counted each call, and then the remaining Args (without T) are passed to the next recursive call; The recursion stops when no types are left and the first specialization is matched, which returns 0. This all happens at compile time, the static member count::value will contain the nr of elements in the argument pack. – Emile Vrijdags Feb 16 '19 at 08:16