Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > variable argument lists

Reply
Thread Tools

variable argument lists

 
 
deathwillendthiswar@gmail.com
Guest
Posts: n/a
 
      11-26-2008
Hi,

I'm not too keen on variable argument lists, but I'd like to use them
for some logging functions.
Suppose the prototype for logging functions is

void Log( const String& sMessage, const int iLevel, const bool
bUseLineEnd );

String already takes variable argument lists in it's sPrintf function,
which also returns a reference to this, so I could use

Log( String().sPrintf( "test %d", 5 ), level, true ); for example.

That's not really a problem, but what happens: String is constructed,
then allocates memory, then calls sprintf and returns a reference to
itself. Internally, Log copies the memory from String into pre-
allocated space. The call returns, and String and it's memory are
deallocated.
What I would rather like to see, is that the sprintf call happens
directly on the pre-allocated memory in Log. That saves allocating,
memcpy and deallocation. However, I would also like to keep the same
prototype, so that I can use Log( "test %d", 5, level, true );

Variable arguments can't be listed first, so my first thought was to
simply declare all possible functions:

template< class T0 >
void Log( const char* Format, const T0 arg0, const int iLevel, const
bool bLineEnd );
template< class T0, class T1 >
void Log( const char* Format, const T0 arg0, const T1 arg1, const int
iLevel, const bool bLineEnd );

and so on.
Implementating this was easy at first sight: let the Logger class have
a method that accepts a va_list and construct the list from the
arguments.
template< class T0 >
void Log( const char* Format, const T0 arg0, const int iLevel, const
bool bLineEnd )
{
va_list args;
va_start( args, Format );
InternalLogFunction( Format, args, iLevel, bLineEnd );
va_end( args );
}

This does excatly what I want, though it's not overly pretty, but gcc
(4.1.2) chokes on this saying "va_start used in function with fixed
args".
I don't really understand why it is not allowed (afaik va_start just
lets args point to the next element on the stack, arg0 in this case),
can someone explain this?
Also, what would be other ways to achieve this? What I basically want
is a variable argument list of some kind, followed by 2 named
parameters. (ok I could just use Log( const int, const bool, const
char*, ... ) but it would just make writing much easier if it behaved
like the non-printf Log)

Thanks!
 
Reply With Quote
 
 
 
 
Larry Evans
Guest
Posts: n/a
 
      11-26-2008
On 11/26/08 10:06, wrote:
[snip]
> Variable arguments can't be listed first, so my first thought was to
> simply declare all possible functions:
>
> template< class T0 >
> void Log( const char* Format, const T0 arg0, const int iLevel, const
> bool bLineEnd );
> template< class T0, class T1 >
> void Log( const char* Format, const T0 arg0, const T1 arg1, const int
> iLevel, const bool bLineEnd );
>
> and so on.
> Implementating this was easy at first sight: let the Logger class have
> a method that accepts a va_list and construct the list from the
> arguments.
> template< class T0 >
> void Log( const char* Format, const T0 arg0, const int iLevel, const
> bool bLineEnd )
> {
> va_list args;
> va_start( args, Format );
> InternalLogFunction( Format, args, iLevel, bLineEnd );
> va_end( args );
> }
>
> This does excatly what I want, though it's not overly pretty, but gcc
> (4.1.2) chokes on this saying "va_start used in function with fixed
> args".

[snip]

Section 3.2 of:

http://www.open-std.org/jtc1/sc22/wg...2004/n1704.pdf

shows printf implementation using variadic templates. Maybe you
could emulate that if using gcc and variadic templates is acceptable
to you.
 
Reply With Quote
 
 
 
 
gyakoo
Guest
Posts: n/a
 
      11-26-2008
Another form is to overload the single comma operator (,) of an
object. Yes, it is a strange form.
If the comma operator returns a reference to the object itself, you
could be something like:

(this code is neither tested nor compiled (I'm writing it on the fly),
and it isn't efficient, in fact it is only a wrapper syntax to pass
directly a vector to a function, but I think that it is interesting as
alternative, at least you could use the main idea behind comma
operator overload.)

// Overloading comma operator.
// ---------------------------
class object
{
public:
object( int val ){ values.push_back( val ); }

object& operator ,( const object& obj )
{
std::copy( obj.values.begin(), obj.values.end(),
std::back_inserter( values ) );
return *this;
}
object& operator ,( int v )
{
values.push_back( v );
return *this;
}
protected:
std::vector< int > values;
};

void func( const object& obj )
{
}

// using it
func ( object(5), 3, 4, 5 );



On Nov 26, 6:26*pm, Larry Evans <cppljev...@suddenlink.net> wrote:
> On 11/26/08 10:06, deathwillendthis...@gmail.com wrote:
> [snip]
>
> > Variable arguments can't be listed first, so my first thought was to
> > simply declare all possible functions:

>
> > template< class T0 >
> > void Log( const char* Format, const T0 arg0, const int iLevel, const
> > bool bLineEnd );
> > template< class T0, class T1 >
> > void Log( const char* Format, const T0 arg0, const T1 arg1, const int
> > iLevel, const bool bLineEnd );

>
> > and so on.
> > Implementating this was easy at first sight: let the Logger class have
> > a method that accepts a va_list and construct the list from the
> > arguments.
> > template< class T0 >
> > void Log( const char* Format, const T0 arg0, const int iLevel, const
> > bool bLineEnd )
> > {
> > va_list args;
> > va_start( args, Format );
> > InternalLogFunction( Format, args, iLevel, bLineEnd );
> > va_end( args );
> > }

>
> > This does excatly what I want, though it's not overly pretty, but gcc
> > (4.1.2) chokes on this saying "va_start used in function with fixed
> > args".

>
> [snip]
>
> Section 3.2 of:
>
> * *http://www.open-std.org/jtc1/sc22/wg...2004/n1704.pdf
>
> shows printf implementation using variadic templates. *Maybe you
> could emulate that if using gcc and variadic templates is acceptable
> to you.


 
Reply With Quote
 
peter koch
Guest
Posts: n/a
 
      11-26-2008
On 26 Nov., 17:06, deathwillendthis...@gmail.com wrote:
> Hi,
>
> I'm not too keen on variable argument lists, but I'd like to use them
> for some logging functions.
> Suppose the prototype for logging functions is
>
> void Log( const String& sMessage, const int iLevel, const bool
> bUseLineEnd );
>
> String already takes variable argument lists in it's sPrintf function,
> which also returns a reference to this, so I could use
>
> Log( String().sPrintf( "test %d", 5 ), level, true ); for example.
>
> That's not really a problem, but what happens: String is constructed,
> then allocates memory, then calls sprintf and returns a reference to
> itself. Internally, Log copies the memory from String into pre-
> allocated space. The call returns, and String and it's memory are
> deallocated.


Why not just imitate the stream iterators found in the standard
library? You could do that very easily by using a std::stringstream
and then - if performance requires it - replace it with your own
"stream", that goes directly to the underlying buffer without any
additional use of dynamic memory.

/Peter
 
Reply With Quote
 
deathwillendthiswar@gmail.com
Guest
Posts: n/a
 
      11-27-2008
[ hmm, seems I misunderstood "Reply To Author", sorry for that, here's
what I wanted to say in short: ]

Nice tip about overloading comma operator, didn't even know that is
was defined.

I already got a similair solution to stream iterators from a collegue.
You mean something like
void Log( const char* Format, const T0 arg0, const T1 arg1, const int
iLevel, const bool bLineEnd )
{
InternalLogStream( iLevel, bLineEnd, Format ) << arg0 << arg1;
Flush();
}

right?
I like the templates: there's no way you can write a call with an
argument that doesn't support conversion as the compiler would spot it
immedeately so it's safer than normal printf. But wouldn't it require
me to rewrite/reinvent the printf machanism? Ever call to << would
have to move to the next '%', then do the appropriate conversion to
the internal string. That's exactly what printf() does.
nonetheless, interesting solution.

I came up with something myself, it's more of a quick hack but works
fine:
template< class T0, class T1 >
void Log( const char* fmt, const T0 arg0, const T1 arg1, const int
iLevel, const bool bLineEnd )
{
InternalString.Printf( fmt, arg0, arg1 );
Log( InternalString, iLevel, bLineEnd );
}

Thanks!
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Variable argument function as a parameter of a variable argument function AikidoGuy C Programming 11 11-21-2011 10:43 PM
List of lists of lists of lists... =?UTF-8?B?w4FuZ2VsIEd1dGnDqXJyZXogUm9kcsOtZ3Vleg==?= Python 5 05-15-2006 11:47 AM
Function pointers, variable argument functions calling other variable-argument functions (sort of) S?ren Gammelmark C Programming 1 01-07-2005 09:41 PM
How to pass variable argument list to another function w/ variable argument list? Ben Kial C Programming 1 11-15-2004 01:51 AM
Variable argument lists Anders Andersen C Programming 3 11-17-2003 05:01 AM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57