Topic: template varargs


Author: 5045-2h8p@spamex.com (Alexander Nasonov)
Date: 02 Apr 02 05:48:28 GMT
Raw View
Phil Brooks <phil_brooks@mentorg.com> wrote in message
news:<3CA0BC6E.94A43D4A@mentor.com>...
> It seems to me that some sort of template varargs support would
> finally create the possibility of doing type safe formatted io
> in C++ that can give comparable performance (or possibly beat)
> C style formatted io.   In my opinion this is one of the biggest
> shortcomings in C++.  (so in my opinion should have a high
> priority for consideration in new C++ development).

I agree

> It seems to me that it should allow, in the spirit of templates,
> all of the runtime overhead to be boiled away at compile time.
> Does your proposal do that?

No, it doesn't. I didn't proposed template varying arguments like
Dylan Nicholson did when he started this thread. I have an alternative
solution to extend ordinary function definition/declaration with
type-safe varying arguments. Just take a look at this declaration:

void echo(ostream & os, ... varargs<writer, arg_holder> va); // This
is not C++ 98!

It is ordinary function with varying number of arguments. Every time
compiler found this function call it create temporary for every
varying argument, maintain array of pointers and call it. For example:

echo(cout,    0', 1, "two");

becomes:

arg_holder<char> __arg1(   0');
arg_holder<int> __arg2(1);
arg_holder<const char [4]> __arg3("two");

varargs<writer, arg_holder> __va; // store pointers to writer
va.push_back(&__arg1); // implicit cast to writer *
va.push_back(&__arg2);
va.push_back(&__arg3);

echo(cout, __va); // pointers to all varying arguments stored in __va

To use __va effectively inside the echo function you need virtual
functions (writer::write in this example). This is overhead. If    echo'
function were function template you could ever strip writer::write
function calls. On the other hand you might discover that your program
has huge executable size. This is drawback of function templates. For
widely used functions (like printf) that are called many times with
different arguments it's a big problem. Additionally, unlike template
varying arguments my alternative is quite small and clear.

Alexander Nasonov
email = 'alnsn' + '@' + 'mail' + '.' + 'ru'

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]




Author: Phil Brooks <phil_brooks@mentorg.com>
Date: 31 Mar 2002 06:54:30 -0500
Raw View
I looked at it for a bit.  The problem is that it is comparing both
sorting via qsort (where C is slower than templatized C++ sorting)
and formatted io (where C is faster).

When you compare strict io, the advantage C has performance
wise adds up quickly, especially if you are using a lot of arguments:

Your example:

>     std::cout << a << " + " << b << " = " << a+b << std::endl;
 results in 6 separate virtual function calls.

The C equivalent

>     printf( "%d + %d = %d\n", a, b, a+b );
results in 1 non-virtual function call and some run time scanning of the
format string.  I have improved performance critical output loops by
a factor of 4x in such cases by converting from C++ io to C io.  There
isn't anything that a compiler writer or library implementer can do to
optimize around the fundamental C function calling mechanism.

> Really?   I've always rather liked writing
>
>     std::cout << a << " + " << b << " = " << a+b << std::endl;

What if you could write

      std::cout.formatted_write( a, "+", b, " = ", a+b, std::endl );

and have it run even _faster_ than printf, and be just as type safe
as your cout statement?  This should be possible with templatized
varargs type functionality that is being proposed here.

Phil

Richard Smith wrote:
>
> "Phil Brooks" <phil_brooks@mentorg.com> wrote in message
> news:3CA0BC6E.94A43D4A@mentor.com...
> > It seems to me that some sort of template varargs support would
> > finally create the possibility of doing type safe formatted io
> > in C++ that can give comparable performance (or possibly beat)
> > C style formatted io.
>
> Have you read Stroustrup's paper "Learning Standard C++ as a New Language"?
> [ http://www.research.att.com/~bs/new_learning.pdf ].  The performances he
> gives suggest a very favourable (to C++) comparison between C and C++-stream
> I/O.
>
> > In my opinion this is one of the biggest
> > shortcomings in C++.  (so in my opinion should have a high
> > priority for consideration in new C++ development).
>
> Really?   I've always rather liked writing
>
>     std::cout << a << " + " << b << " = " << a+b << std::endl;
>
> and such like.  It's clearer (and no less efficient) than the C style
>
>     printf( "%d + %d = %d\n", a, b, a+b );
>
> --
> Richard Smith
>
>       [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
>       [ about comp.lang.c++.moderated. First time posters: do this! ]
>
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
> [ Note that the FAQ URL has changed!  Please update your bookmarks.     ]
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Richard Smith" <richard@ex-parrot.com>
Date: 28 Mar 02 06:12:20 GMT
Raw View
"Phil Brooks" <phil_brooks@mentorg.com> wrote in message
news:3CA0BC6E.94A43D4A@mentor.com...
> It seems to me that some sort of template varargs support would
> finally create the possibility of doing type safe formatted io
> in C++ that can give comparable performance (or possibly beat)
> C style formatted io.

Have you read Stroustrup's paper "Learning Standard C++ as a New Language"?
[ http://www.research.att.com/~bs/new_learning.pdf ].  The performances he
gives suggest a very favourable (to C++) comparison between C and C++-stream
I/O.

> In my opinion this is one of the biggest
> shortcomings in C++.  (so in my opinion should have a high
> priority for consideration in new C++ development).

Really?   I've always rather liked writing

    std::cout << a << " + " << b << " = " << a+b << std::endl;

and such like.  It's clearer (and no less efficient) than the C style

    printf( "%d + %d = %d\n", a, b, a+b );

--
Richard Smith



      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]




Author: Phil Brooks <phil_brooks@mentorg.com>
Date: 27 Mar 2002 07:38:40 -0500
Raw View
It seems to me that some sort of template varargs support would
finally create the possibility of doing type safe formatted io
in C++ that can give comparable performance (or possibly beat)
C style formatted io.   In my opinion this is one of the biggest
shortcomings in C++.  (so in my opinion should have a high
priority for consideration in new C++ development).

It seems to me that it should allow, in the spirit of templates,
all of the runtime overhead to be boiled away at compile time.
Does your proposal do that?

Alexander Nasonov wrote:
>
> I'm trying to solve this problem for the format function. I'm
> implmeneting it as background task at
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: 5045-2h8p@spamex.com (Alexander Nasonov)
Date: 18 Mar 02 05:49:22 GMT
Raw View
I'm trying to solve this problem for the format function. I'm
implmeneting it as background task at
http://cpp-experiment.sourceforge.net (there is no release yet).
For users, it's look like this:
   string s = format("<1><2><3><4><5>", 1, '2', "three")(4, 5);
Basic idea is using chain of temporaries returned by format and
following overloaded call operators. Every temporary store pointers to
argument and pointers to write function. Last temporary in chain is
then converted into string. Unfortunately, implemention is difficult.
Personally, I would like language support for template varargs.
Imagine that you have pseudo-template pseudo-defined as:
template<class ArgInterface, template<template T> class ArgHolder>
varargs {
   ArgInterface * args_[VARARG_COUNT];
   size_t size() const {
      return VARARG_COUNT;
   }
   ArgInterface * operator[](size_t index) const {
      return args_[index];
   }
};

ArgInterface must be a public base class of ArgHolder<T> for any
T.
This pseudo-template is supported by compiler. Its support really is:
1. Create temporary for every varying argument:
   const T & __arg = current_argument;
   ArgHolder<T> __temp(__arg);
2. Maintain array of pointers to ArgInterface pointed to those temporaries

Example.
Echoing all varargs to a stream:

struct writer { // ArgInterface
   virtual void write(ostream & os) const = 0;
   virtual ~writer() {}
};


template<typename T>
struct arg_holder : writer // ArgHolder
{
   const T & arg_;
   arg_holder(const T & arg) : arg_(arg) {}
   virtual void write(ostream & os) const {
      os << arg_;
   }
};

void echo(ostream & os, ... varargs<writer, arg_holder> va)
{
   for(size_t i = 0; i < va.size(); ++i) {
      writer * w = va[i];
      w->write(os);
      os << ' ';
   }
}

int main()
{
   echo(cout, '0', 1, "two");
   cout << endl;
}

Output: 0 1 two

Alexander Nasonov
email = 'alnsn' + '@' + 'mail' + '.' + 'ru'

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]




Author: dylan@moldflow.com (Dylan Nicholson)
Date: 13 Mar 2002 08:32:32 -0500
Raw View
This is been brought up many times before but I was just wondering
what ideas were floating about and whether something like this was
likely to make it into a future revision.

Basically the problem seems to be one of notation.
The simplest case is

template <class A>
void foo(A a)
{
  /* ... */
  bar(a);
  /* ... */

}

template <class A, class B>
void foo(A a, B b)
{
  /* ... */
  bar(a, b);
  /* ... */
}

etc. etc.  You could imagine a syntax like

template <...>
void foo(...)
{
  /* ... */
  bar(...);
  /* ... */
}

might be workable.  For a class:

template <class R, ...>
struct foo
{
  typedef R (*func)(...);
  void foo(func f) : m_func(f) { }
  R operator ()(...)
  {
      return m_func(...);
  }
private:
  func m_func;
};

But if I wanted to do:

template <class A>
void foo(A a)
{
  cout << a << '\n';
}

template <class A, class B>
void foo(A a, B b)
{
  cout << a << b << '\n';
}

etc. etc.,  I'd be in trouble.

I would like to able to do:

template <class A, ...>
void foo(A a, ...)
{
  cout << a; foo(...);
}

template <>
void foo()
{
  cout << '\n';
}

which would give cout << a; cout << b; ... cout << '\n';  Not quite
the same, but probably close enough for most uses.

Has anyone else given this some serious thought recently?

Dylan
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]