I'm aware that sizeof...(Args...)
yields the number of types in a C++0x packed template argument list, but I wanted to implement it in terms of other features for demonstation purposes, but it won't compile.
// This is not a solution -- overload ambiguity.
// template <typename... Args> size_t num_args (); // Line 7
// template <>
constexpr size_t num_args ()
{
return 0;
}
template <typename H, typename... T>
constexpr size_t num_args () // Line 16
{
return 1 + num_args <T...> (); // *HERE*
}
int main ()
{
std :: cout << num_args <int, int, int> ();
}
This errors at *HERE*
with
No matching function call to ...
... candidate is template<class H, class ... T> size_t num_args()
i.e. it's not seeing the base case which is defined first. Forward-declaring template<typename...T>num_args();
introduces ambiguity in overload resolution.
x.cpp:30:45: note: candidates are:
x.cpp:7:36: note: size_t num_args() [with Args = {int, float, char}, size_t = long unsigned int]
x.cpp:16:9: note: size_t num_args() [with H = int, T = {float, char}, size_t = long unsigned int]
I am using gcc 4.6. How can I make this work?
Thanks.
You didn’t declare a base case. You have a template-free overload of your
num_args
function but when calling a functionnum_args<T...>()
this will never be found, for obvious reasons: it will always try to instantiate a function template.You can however specialise your function template to perform the desired operation.
However, this won’t work either since here you’re specialising a parameterless function template and such a template doesn’t exist: your other function template
num_args
always has at least one argument,H
.In order to really make this work you need partial specialisations, and these only exist for class templates. So this is what you need here.
Konrad's answer should get you going, but I think the more idiomatic way such things are usually expressed is with static member constants, so I just wanted to present that solution:
Then you get your argument pack size via
arg_size<Args...>::value
.