3

Trying to respond to another question, and for fun, I've written the following silly program that try to convert an old C-style variadic function arguments list with a new one C++-style variadic template argument list (also in wandbox)

#include <cstdarg>
#include <iostream>
#include <stdexcept>

template <typename ... Args>
void bar (Args const & ... args)
 { 
   using unused = int[];

   (void)unused { (std::cout << args << ", ", 0)... };

   std::cout << std::endl;
 }

template <typename ... Ts>
void foo (int num, ...)
 {
   if ( num != sizeof...(Ts) )
      throw std::runtime_error("!");

   va_list args;                     

   va_start(args, num);           

   bar( va_arg(args, Ts)... );

   va_end(args);
 }

int main ()
 {
   foo<int, long, long long>(3, 1, 2L, 3LL); // print 1, 2, 3, 
 }

But clang++ and execute it without problem, g++ give the following error

prog.cc: In function 'void foo(int, ...)':
prog.cc:26:25: error: expansion pattern 'va_arg(args, Ts)' contains no argument packs
    bar( va_arg(args, Ts)... );
                         ^~~

As usual: who's right? g++ or clang++?

ADDENDUM

Changing the line

 bar( va_arg(args, Ts)... );

in

 bar( ((void)Ts{}, va_arg(args, Ts))... );

the program is compiled by both compilers but, executing it, the clang++ version print

1, 2, 3,

(as espected) when the g++ version revert the values and print

3, 2, 1,
Community
  • 1
  • 1
max66
  • 65,235
  • 10
  • 71
  • 111
  • `va_arg` is a macro, it's not supposed to be used the way you use it. Both compilers are right. – Kerrek SB Feb 18 '17 at 18:34
  • And in any case the evaluation order of function arguments is unspecified, so this doesn't work. – Kerrek SB Feb 18 '17 at 18:43
  • @KerrekSB - thanks; I suppose that your second comment respond also to the "addendum" I've just added. Please, could you write your comments as an answer? – max66 Feb 18 '17 at 18:47
  • You can also try just `(va_arg(args, Ts))...`. That might suffice. – Kerrek SB Feb 18 '17 at 18:51
  • @KerrekSB - Uhmm... no: I've tried but g++ give me a compilation error also with `(va_arg(args, Ts))...` – max66 Feb 18 '17 at 18:53
  • The C specification says *"The parameter `type` shall be a type name specified such that the type of a pointer to an object that has the specified type can be obtained simply by postfixing a `*` to `type`"* – Johannes Schaub - litb Feb 18 '17 at 19:07
  • Therefore I would not say that it needs to be valid. The C++ spec says nothing about what shall happen if you pass a dependent type. Or if you pass something like `decltype(...)`, which is not "a type name", so it will not satisfy the requirement put by the C spec. The best that I would concede to that usage is that it might work on some implementations, and not on others. It would be better if C++ specified what happens though. – Johannes Schaub - litb Feb 18 '17 at 19:09
  • On the other side, the thing with "name" is that in C IIRC there is no definition of the term "name", so when C says "type name", it could also cover things like `decltype(...)` in C++. Because arguments like `char*` need to be acceptable aswell, even though those are not "names" in C++, which has this term defined precisely – Johannes Schaub - litb Feb 18 '17 at 19:16
  • @max66 maybe you could utilize [tuple tag dispatch with index sequence](http://melpon.org/wandbox/permlink/mHPruVEsPxhSkWMh) as a workaround? It looks like it works as expected in both gcc and clang... – W.F. Feb 18 '17 at 19:46
  • @W.F. - Interesting but I'm more confused as ever: why g++ give the value in the correct order passing they in a `std::tuple` object usign the same expression, to initualize the `std::tuple`, that revert the values, when passes to `bar()`? – max66 Feb 18 '17 at 20:07
  • @max66 According to [this](http://stackoverflow.com/questions/2934904/order-of-evaluation-in-c-function-parameters) order of evaluation of expressions passed as parameters are undefined. On the other hand according to [this](http://stackoverflow.com/questions/17381573/order-of-evaluation-of-arguments-to-a-constructor) order of evaluation expressions in the braces of constructor initializer is left to right... This may be the cause – W.F. Feb 19 '17 at 10:31

0 Answers0