variable argument lists

Discussion in 'C++' started by deathwillendthiswar@gmail.com, Nov 26, 2008.

  1. Guest

    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!
    , Nov 26, 2008
    #1
    1. Advertising

  2. Larry Evans Guest

    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/wg21/docs/papers/2004/n1704.pdf

    shows printf implementation using variadic templates. Maybe you
    could emulate that if using gcc and variadic templates is acceptable
    to you.
    Larry Evans, Nov 26, 2008
    #2
    1. Advertising

  3. gyakoo Guest

    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 <> wrote:
    > 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/wg21/docs/papers/2004/n1704.pdf
    >
    > shows printf implementation using variadic templates.  Maybe you
    > could emulate that if using gcc and variadic templates is acceptable
    > to you.
    gyakoo, Nov 26, 2008
    #3
  4. peter koch Guest

    On 26 Nov., 17:06, 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
    peter koch, Nov 26, 2008
    #4
  5. Guest

    [ 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!
    , Nov 27, 2008
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Anders Andersen

    Variable argument lists

    Anders Andersen, Nov 16, 2003, in forum: C Programming
    Replies:
    3
    Views:
    301
    Gabor Drasny
    Nov 17, 2003
  2. =?UTF-8?B?w4FuZ2VsIEd1dGnDqXJyZXogUm9kcsOtZ3Vleg==

    List of lists of lists of lists...

    =?UTF-8?B?w4FuZ2VsIEd1dGnDqXJyZXogUm9kcsOtZ3Vleg==, May 8, 2006, in forum: Python
    Replies:
    5
    Views:
    390
    =?UTF-8?B?w4FuZ2VsIEd1dGnDqXJyZXogUm9kcsOtZ3Vleg==
    May 15, 2006
  3. Ben Kial
    Replies:
    1
    Views:
    635
    Eric Enright
    Nov 15, 2004
  4. S?ren Gammelmark
    Replies:
    1
    Views:
    1,871
    Eric Sosman
    Jan 7, 2005
  5. AikidoGuy
    Replies:
    11
    Views:
    550
    Seebs
    Nov 21, 2011
Loading...

Share This Page