I noticed, that both GCC and MSVC are happy with the following code:
#include <iostream>
void foo(...);
int main()
{
foo();
}
void foo(...)
{
std::cout << "foo\n";
}
More specifically, code was run under GCC 6.2.0 and Visual Studio 2015.
I know that C requires at least one named parameter preceding the ellipsis, which allows to handle any number of arguments using specialized va_start, va_args, and va_end macros from <stdarg.h> (here <cstdarg>) header. Otherwise, it won't even compile.
Does C++ have some special treatment for "pure ellipsis" form or is it not suitable for fetching the arguments, i.e. it's allowed, but completely impractical?
C++ Variadiac arguments are explained here. This syntax is supported in C++, but the arguments are not accessible:
In the C programming language, at least one named parameter must appear before the ellipsis parameter, so printz(...); is not valid.
In C++, this form is allowed even though the arguments passed to such
function are not accessible, and is commonly used as the fallback
overload in SFINAE, exploiting the lowest priority of the ellipsis
conversion in overload resolution. This syntax for variadic arguments
was introduced in 1987 C++ without the comma before the ellipsis. When
C89 adopted function prototypes from C++, it replaced the syntax with
one requiring the comma. For compatibility, C++98 accepts both
C++-style f(int n...) and C-style f(int n, ...)
In C++ it is allowed because even if there is no named parameter before, the ... will only be an inaccessible variadic argument.
In C, there is no overloads, and having a function that receives only ... can be a great source of runtime error. Inaccessible varargs is not useful is C.
In C++, it is currently use as a sink function for sfinae. Compilers will always choose other overload if possible before resolving a call to a function with variadic parameter. It is pratical for sfinae purpose:
template<typename F, typename... Ts>
struct is_callable {
private:
template<typename T, typename... Args>
static decltype(
static_cast<void>(std::declval<T>()(std::declval<Args>()...)),
std::true_type{}
) test(int);
template<typename...>
static std::false_type test(...); // not a template variadic, classic vararg here.
public:
// Here, the compiler will try the first version of the function
// Because '...' is not the preferred overload
// If the return type expression don't yield to a type, the compiler
// will have no choice but to pick the variadic one,
// resulting in a std::false_type
using type = decltype(test<F, Ts...>(0));
};
Related
What are the rules for the selection of overloaded function templates in case of non-type template parameters, if one of the parameters is a placeholder type. I am confused with the current behavior of the compilers, consider the next example:
template<int N> struct A{};
template<auto... N> void f(A<N...>);
template<int N> void f(A<N>) {}
template<auto N> void g(A<N>);
template<int N> void g(A<N>) {}
int main() {
f( A<1>{} ); // ok in GCC and Clang, error in MSVC
g( A<1>{} ); // ok in GCC, error in Clang and MSVC
}
Here MSVC fails to select between both sets of overloads. On the other hand, GCC always selects the function template with the more concrete type <int>. And Clang is somewhat in the middle, preferring <int> over the parameter pack <auto...>, but it sees ambiguity during selection between <int> and <auto> overloads. Online demo: https://gcc.godbolt.org/z/4EK99Gjhx
Which one of the behaviors is correct or the standard is not clear about it?
This is likely underspecified, but we can explain the general behavior of implementations with partial ordering rules. In [temp.func.order], it is said that
To produce the transformed template, for each type, non-type, or template template parameter (including template parameter packs thereof) synthesize a unique type, value, or class template respectively and substitute it for each occurrence of that parameter in the function type of the template.
[Note 1: The type replacing the placeholder in the type of the value synthesized for a non-type template parameter is also a unique synthesized type. — end note]
I highlighted the note, which makes it explicit that the transformed template for g<auto> is invalid, since A requires an int argument, but receives a value of synthesized type†.
Consequently, the deduction from the g<int> template to the g<auto> template works but not vice versa, so g<int> is deemed more specialized. I.e. I believe Clang to be in the wrong on g.
For f we have the simpler rule from [temp.deduct.type]/9.2 that governs partial ordering of specializations, and would make the variadic overload more specialized even when replacing auto by int.
† I can't find anything in the wording about invalid transformed templates, only a related clause from P0522 which clarifies that an invalid rewritten form causes the rewritten template not to be at least as specialized (the intuitive behavior for partial ordering, too). But even if we assumed that A could accept an arbitrarily typed value, i.e. had itself an auto parameter, and if we adjust the code accordingly, the partial ordering still works the same on GCC.
I have a custom logger that uses a logger->logf(format, ...) style varargs method for logging. I have object handles that are wrappers around pointers. I have a special format specifier to print the objects ( with a toString() method like in Java)
The "handles" are not "trivially copyable" as they can be constructed from a number of input types, and have converter-cast operators that return the pointer to the contained object type. ( similar to ComPtr<> )
IN windows C++ I can just pass the handle in and the varags method sees the pointer. GCC considers this an error now. The handle is "sizeof(void *)"
Is there a way to get GCC to allow this on a varags method?
Is there a way to specify a special operator xx () method to be passed into a varargs method?
I have a rather large library with a lot of log lines in it and redoing all of them with operator + or operator << would be an intense chore.
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Well if does look like the Variadic template is what I need to use but I have yet to figure out how to make it simple an elegant.
The essence of an algorithm would be
place object or buffer on stack (ideally based on the number of arguments)
add all the arguments to the object.
on the last argument add it to the object, as well and process the arguments.
The "recursive" nature of a variadic template makes a nice way to do this a bit to figure out.
#
Ok I bit the bullet and rewrote the formatter part to use variadic templates. It did take 3 days. Basically it involves having an "Arg" class that has a union of all the primitive types and a "type" field set by the constructor overload for each type.
Then a variadic template to "load a list" of args which is passed to the formatters equivalent of "vsprintf". Great as there is enough information to be runtime type safe. The quastion now is HOW much code bloat is there with the template expansion. As all they do is cast and the "Arg" is a fixed size and it's constructor just loads two fields, type and value. Will GCC and MSC nicely optimize all of it out so there aren't 2 ^ maxArgs full expansions of the variadic templates.
template <typename... Args>
int writef(const wchar_t *fmt, ...) {
FormatfArglist<sizeof...(Args)> arglist;
FormatfArgBase::addArgs(arglist.args(), args...);
return(vwritef(fmt, arglist));
}
template <typename First, typename... Rest>
static void FormatfArgBase::addArgs(Arg *arglist,
const First &first, const Rest &... rest) {
setArg(arglist,Arg(first));
if(sizeof... (Rest) > 0) {
addArgs(++arglist, rest...); // recursive call using pack expansion syntax
}
}
Seems as the C++ guys pile on restrictions on the old C ellipsis one really has to use Variadic templates to get full functionality.
So I bit the bullet and rewrote the formatter part to use variadic templates. It did take 3 days. Basically it involves having an "Arg" class that has a union of all the primitive types and a "type" field set by the constructor overload for each type.
Then a variadic template to "load a list" of args which is passed to the formatters equivalent of "vsprintf". Great as there is enough information to be runtime type safe. The question now is HOW much code bloat is there with the template expansion. As all they do is cast and the "Arg" is a fixed size and it's constructor just loads two fields, type and value. Will GCC and MSC nicely optimize all of it out so there aren't 2 ^ maxArgs full expansions of the variadic templates?
// This is in a "TextWriter" class
template <typename... Args>
int writef(const wchar_t *fmt, ...) {
FormatfArglist<sizeof...(Args)> arglist;
FormatfArgBase::addArgs(arglist.args(), args...);
return(vwritef(fmt, arglist));
}
template <typename First, typename... Rest>
static void FormatfArgBase::addArgs(Arg *arglist,
const First &first, const Rest &... rest) {
setArg(arglist,Arg(first));
if(sizeof... (Rest) > 0) {
addArgs(++arglist, rest...); // recursive call using pack expansion syntax
}
}
I am not sure why it works with Microsoft compiler. The standard clearly indicates, that
Only arithmetic, enumeration, pointer, pointer to member, and class
type arguments are allowed.
(http://en.cppreference.com/w/cpp/language/variadic_arguments).
For your particular case, I suggest you use variadic template function as an intermediate step to convert those values to pointers, and than call your Log function (which I imagine can't be template itself).
This question already has answers here:
What is the meaning of "... ..." token? i.e. double ellipsis operator on parameter pack
(2 answers)
Closed 8 years ago.
While looking at this question I found myself in the cpp reference site where I noticed a strange and new to me syntax :
template<class Ret, class... Args>
struct is_function<Ret(Args......)volatile &&> : std::true_type {};
Yep, 6 dots ! Initially I thought this was a typo, but after checking the libstdc++ source again there it was eg at line 444 :
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes......) volatile &&> : public true_type { };
Is this a valid syntax ? Dot dot dot, are used to pack and unpack parameter packs ? What do 6 dots do ?
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 “...”. [...]
In this case, the two are for different purposes. The first is for parameter pack expansion and the second is for variable argument lists. That particular declaration is to handle functions which take some regular parameters plus a variable argument list.
The difference is between run-time and compile-time variability. A function which takes a variable number of arguments at run-time is special. It is a single function which can handle a variable number of arguments from the caller:
void f(int x,...) // equivalent to void f(int x ...)
{
// Do some run-time logic here to determine what to
// do with parameters after x.
}
This is distinct from the notion that we want to be able to have a template which uses a variety of functions with various parameters which are known at compile time. For example, we could define a function template which takes a pointer to a function and allow the number and types of the arguments to vary:
template <typename... Args>
void g(void (*function_ptr)(Args...))
{
// We can do logic here to call function_ptr with the proper
// number of arguments.
}
Given these functions:
void f1(int);
void f2(int,float);
You can call g with any of them:
g(f1); // fine
g(f2); // also fine
However
g(f); // error
The compiler wouldn't know what to use for the Args parameter pack in g.
I don't understand how the following feature should be used. When I call A::f I can omit the template parameters, but I don't understand why.
template <typename... Args>
struct A
{
template <Args...>
void f() {}
};
int main()
{
A<int, bool> a;
a.f();
}
To be specific, what does the template <Args...> mean and why can I leave the template parameters out of the function call to f?
template<typename ...Args> is a variadic template. It means, that you can specify any number of template type parameters, but I think you already know this.
Whenever Args... appears in the template code, it will be unpacked ("expanded") to the types of the instantiation. In your example, this is int, bool. So your class becomes, when fully expanded, this definition:
struct A<int, bool>
{
template <int, bool>
void f() {}
};
This means, A<int,bool>::f() is again templated (the arguments are unpacked into another template declaration, as you called it), but this time with non-type template parameters with the types int and bool (they're anonymous), so you could instantiate f() for example like this:
a.f<1, true>();
Unfortunately, g++ seems to have a bug and won't accept this piece of code, while it accepts your code.
clang accepts both codes. I expect that in your code, clang doesn't care if the int and bool template parameters are omitted, but it doesn't complain either when they are specified (in contrast to g++).
Usage example:
If you want to use the specified values, they can't be anonymous (obviously). You can, for example, provide a format string in f() which is used to "printf" the template values, like this:
template <Args ...values>
void f(const char *fmt) {
std::printf(fmt, values...);
}
Then, the following code
A<int> a;
a.f<42>("The answer is %d!\n");
will print:
The answer is 42!
But, using the syntax from above (Args... being expanded to anonymous non-type template parameters), the template parameters are essentially useless.
Without specifying values, it still compiles (which surprised me!) and prints an uninitialized int value.
The reason you can leave the template arguments out is because c++11 has template argument deduction template<args ...> is a variadic template which is basically a pack of possibly different typenames. This website explains the omission of template arguments. From reading further into the deduction of non type template arguments, which the compiler can deduce I believe that the compiler is realizing that they are never used (with clang at least) and making it's deduction based on that, read the deducing non type template arguments portion of the website
the following code snippet won't compile under gcc4.6.1:
template <typename... TS>
void do_stuff(TS... ts)
{
auto f = [](TS... things) { };
}
It throws an error stating that the pack things was not expanded. The following code does compile however:
template <typename... TS>
void do_stuff(TS... ts)
{
auto f = [](TS... things...) { };
}
Notice the extra unpacking operator after things inside the parameter list. I've never seen a situation where a variadic pack had to be expanded during its declaration. So my question to you kind folks is:
Is this legal C++0x syntax (the snippet that compiles) or is it just a quirk with GCC when it comes to dealing with variadic types?
Two things:
Yes, GCC is wrong to reject [](TS... things) { }. It's possible that it hasn't been implemented yet.
What you declared by [](TS ... things...) { } is equivalent to [](TS... things, ...). In C++ (not in C), you can leave off the comma before the C-style variadic ellipsis. So instead of doing void printf(char const *fmt, ...) you can declare void printf(char const *fmt...). That's what happens in your lambda. The first ellipsis is the parameter pack unpacking, and the second ellipsis is the C-style variadic ellipsis.