Why does libstdc++
use ... ...
in it's implementation of is_function
? If we check out the cppreference section for std::is_function it gives a sample implementation and says for the first ... ...
case:
// specialization for variadic functions such as std::printf
template<class Ret, class... Args>
struct is_function<Ret(Args......)> : std::true_type {};
so we need the second set of ...
to match a variadic function like printf
:
Comma optional as per 8.3.5 [dcl.fct]
|
v
Ret(Args... ...)
^ ^
| |
Match a function with a variable number of arguments
|
and the function is a variadic function
Note, we have functions like fprintf
that two arguments before the variadic terms and we need to match those as well.
Indeed if we use that implementation and attempt to match printf
without the ... ...
specialization then it fails see it live.
This corner of the language is covered in this post C++11's six dots:
I was mucking around the other day and discovered this nice little oddity:
template <typename... Args>
void foo(Args......);
As it turns out, ...... can be totally valid C++11. This is what happens when backward compatibility mixes with new hotness.
// These are all equivalent.
template <typename... Args> void foo1(Args......);
template <typename... Args> void foo2(Args... ...);
template <typename... Args> void foo3(Args..., ...);
Hopefully the last one shows what is happening here. [...]
Why is this valild? We can see that , ...
is synonymous with ...
from the draft C++11 standard section 8.3.5
[dcl.fct] which has the following grammar:
parameter-declaration-clause:
parameter-declaration-listopt...opt
parameter-declaration-list , ...
and says:
[...] Where syntactically correct and where “...” is not part of
an abstract-declarator, “, ...” is synonymous with “...”. [...]