Operator...

Discussion in 'C++' started by martyn_dobson@hotmail.com, Oct 13, 2008.

  1. Guest

    this has probably been asked/suggested many timtes before, but i just
    thought of it.

    why is there no such thing as something like operator...()
    imho it would allow us to smooth off one of the sharper corners of c+
    +.

    you could maybe do something like this:

    class string
    {
    public:

    const char *operator...() const
    {
    return c_str();
    }
    };


    void foo(const char *format, ...)
    {
    //the usual vaarg stuff
    }


    void bar()
    {
    string s = "test";

    foo("this is a test %s", s);
    }



    just a quick thought,

    M.
     
    , Oct 13, 2008
    #1
    1. Advertising

  2. Guest

    yeah the standard thing is to have to call s.c_str().
    the standards board purposefully didnt put an operator char* into
    string for the reason that you cant make the std::string class act
    entirely like a pod type like in other languages because of variable
    arguments.

    i meant this only as a possible conversion for a class beign passed
    into a variable argument parameter list. its one of those things that
    catches people out, and makes other programmers wonder why c++ isnt
    more helpfull some times.

    just thought it could be a handy little addition.

    M.
     
    , Oct 13, 2008
    #2
    1. Advertising

  3. wrote:
    > this has probably been asked/suggested many timtes before, but i just
    > thought of it.
    >
    > why is there no such thing as something like operator...()
    > imho it would allow us to smooth off one of the sharper corners of c+
    > +.


    The next C++ standard will introduce variadic templates, which will
    allow writing type-safe functions which take a variable amount of
    parameters. I believe that will allow you to do what you are referring
    to here.
     
    Juha Nieminen, Oct 13, 2008
    #3
  4. On Oct 13, 11:10 am, wrote:
    > this has probably been asked/suggested many timtes before, but i just
    > thought of it.
    >
    > why is there no such thing as something like operator...()
    > imho it would allow us to smooth off one of the sharper corners of c+
    > +.
    >
    > you could maybe do something like this:
    >
    > class string
    > {
    > public:
    >
    >         const char *operator...() const
    >         {
    >                 return c_str();
    >         }
    > };
    >
    > void foo(const char *format, ...)
    > {
    >         //the usual vaarg stuff
    >
    > }
    >
    > void bar()
    > {
    >         string s = "test";
    >         foo("this is a test %s", s);
    > }


    I quite like format strings myself because of its concise syntax.
    However, C++ objects do not like to be passed into "...".

    The shortest syntax for passing C++ objects into "..." along with
    formatting them into automatically allocated buffers is prefixing
    objects with an overloaded operator~() (binary negation). This
    overloaded operator allocates a temporary buffer on the stack, formats
    an object into that buffer and returns an argument for "%.*s" format
    string. Obviously, the buffer is only alive till until the full
    expression has been evaluated.

    Please scroll down to main() first to see usage:

    #include <stdio.h>

    // hack: supposed to be layout compatible with arguments for
    "%.*s"
    struct StarString
    {
    int n;
    char* p;
    };

    struct TmpBuf
    {
    char buf[0x100];
    StarString format_arg;

    template<class T>
    TmpBuf(T const& t)
    {
    format_arg.n = sizeof buf;
    format_arg.p = buf;
    format_arg = t.format(format_arg);
    };
    };

    StarString operator~(TmpBuf const& buf)
    {
    return buf.format_arg;
    }

    struct Y
    {
    StarString format(StarString s) const
    {
    s.p = "Hello world from Y";
    s.n = sizeof "Hello world from Y" - 1;
    return s;
    }
    };

    struct X
    {
    StarString format(StarString s) const
    {
    s.n = snprintf(s.p, s.n, "X@%p", this);
    return s;
    }
    };

    int main()
    {
    // what ~Y() does:
    // 1) creates a temporary Y object
    // 2) creates a temporary TmpBuf object
    // 3) calls Y::format() to format the Y object into the
    buffer provided by TmpBuf
    // 4) return StarString which is passed into %.*s instead of
    (int, char*).
    printf("%.*s\n", ~Y());
    printf("%.*s\n", ~X());
    }

    --
    Max
     
    Maxim Yegorushkin, Oct 13, 2008
    #4
  5. Maxim Yegorushkin wrote:
    >
    > [...]
    >
    > struct X
    > {
    > StarString format(StarString s) const
    > {
    > s.n = snprintf(s.p, s.n, "X@%p", this);



    There isn't any snprintf in C++98/03.
     
    Ioannis Vranos, Oct 13, 2008
    #5
  6. On Oct 13, 7:02 pm, Ioannis Vranos <>
    wrote:
    > Maxim Yegorushkin wrote:
    >
    > >     [...]

    >
    > >     struct X
    > >     {
    > >         StarString format(StarString s) const
    > >         {
    > >             s.n = snprintf(s.p, s.n, "X@%p", this);

    >
    > There isn't any snprintf in C++98/03.


    Too bad for the standard ;)))

    --
    Max
     
    Maxim Yegorushkin, Oct 14, 2008
    #6
  7. Maxim Yegorushkin wrote:
    > I quite like format strings myself because of its concise syntax.


    The major problem with printf-style format strings is that they are
    not very abstract. This means that it's very hard to abstract away some
    type because the format string needs to know the exact type, as a string
    (rather than as an overloaded function or whatever).

    I think this example illustrates perfectly the problem with format
    strings:

    template<typename T>
    void foo(const T& value)
    {
    std::cout << value << "\n"; // ok

    std::printf("%???\n", value); // What to put here???
    }

    Of course templated functions are not the only situation where the
    lack of abstraction of format strings can hit you hard. It's enough to
    have typedeffed some type, which you later want to print. (Sure, you can
    try to struggle by also #defining the format string for that type, but
    that's awkward and has a multitude of problems in itself.)

    If I'm not mistaken, the next C++ standard will introduce a feature
    which will allow an abstract and type-safe way of giving a variable
    amount of parameters to a function, with the so-called variadic templates.
     
    Juha Nieminen, Oct 14, 2008
    #7
  8. On Oct 14, 1:15 pm, Juha Nieminen <> wrote:
    > Maxim Yegorushkin wrote:
    > > I quite like format strings myself because of its concise syntax.

    >
    >   The major problem with printf-style format strings is that they are
    > not very abstract. This means that it's very hard to abstract away some
    > type because the format string needs to know the exact type, as a string
    > (rather than as an overloaded function or whatever).
    >
    >   I think this example illustrates perfectly the problem with format
    > strings:
    >
    > template<typename T>
    > void foo(const T& value)
    > {
    >     std::cout << value << "\n"; // ok
    >     std::printf("%???\n", value); // What to put here???
    > }


    You put %s in there because it does not matter what you are
    outputting, what does matter is that you want to have a textual form
    of it.

    The real problem is that C++ does not have a native format mechanism.
    std::eek:stream is just a type safety hack over snprintf() and
    boost::format is another hack over std::eek:stream. In other words, all
    roads lead back into snprintf().

    My dream high-performance C++ formatting mechanism would represent the
    output sequence as an iterator and formatting would emit symbols
    directly into the iterator.

    --
    Max
     
    Maxim Yegorushkin, Oct 14, 2008
    #8
  9. Maxim Yegorushkin wrote:
    > The real problem is that C++ does not have a native format mechanism.
    > std::eek:stream is just a type safety hack over snprintf()


    I disagree. C++ streams are not so much about type safety (well, they
    are about that too, but that's not the *only* thing), but about abstraction.

    The C printf family of function are the hack, not the C++ streams.
    When they designed C they had to invent *some* way of printing different
    types in a way which would be as easy to use as possible. The solution
    was support for variable amount of parameters to a function (which works
    because C was built on stack-based architectures where such a thing is
    feasible) and format strings. Then C compilers spent the next 20+ years
    optimizing the runtime format string interpreters to be as fast as
    possible (which they succeeded in doing pretty well in the end).

    However, that doesn't make the printf functions and format strings
    less of a hack, because they are just that. They are completely
    non-abstract, error-prone and type-unsafe.

    C++ streams are not a hack over printf. C++ streams are a
    *replacement* of printf. A replacement which is intended to be
    everything that the printf functions aren't, ie. abstract, type-safe and
    less error-prone. They allow you to write code which safely uses streams
    without having to know anything about the types being handled.

    Sure, C++ streams might not be as easy to use as could be possible,
    but they are definitely a step to the right direction.

    > and
    > boost::format is another hack over std::eek:stream. In other words, all
    > roads lead back into snprintf().


    Wrong, all roads lead *away* from the printf family of functions,
    because *those* are the real hacks, and while they may work in C, they
    definitely don't work in C++. Not if you need even the slightest amount
    of abstraction.
     
    Juha Nieminen, Oct 14, 2008
    #9
  10. James Kanze Guest

    On Oct 14, 3:13 pm, Maxim Yegorushkin <>
    wrote:
    > On Oct 14, 1:15 pm, Juha Nieminen <> wrote:
    > > Maxim Yegorushkin wrote:
    > > > I quite like format strings myself because of its concise
    > > > syntax.


    > > The major problem with printf-style format strings is that
    > > they are not very abstract. This means that it's very hard
    > > to abstract away some type because the format string needs
    > > to know the exact type, as a string (rather than as an
    > > overloaded function or whatever).


    > > I think this example illustrates perfectly the problem with
    > > format strings:


    > > template<typename T>
    > > void foo(const T& value)
    > > {
    > >     std::cout << value << "\n"; // ok
    > >     std::printf("%???\n", value); // What to put here???
    > > }


    > You put %s in there because it does not matter what you are
    > outputting, what does matter is that you want to have a
    > textual form of it.


    Except that it likely does matter.

    Part of the problem is that in most programs, a single type
    (e.g. double, or int) is used for values with radically
    different semantics (at the user level). You want to specify
    the formatting for each set of semantics program wide, however,
    and not in each print statement. With iostream's, of course,
    you define a manipulator for each semantics, and the job is
    done. Very few other languages I've seen offer this
    possibility, however, which means that you end up embedding such
    critical information deep within the code at many different
    places. (In well written C++, you'll almost never see any of
    the standard manipulators, except perhaps std::setw. Almost
    every value output will be preceded by some application specific
    manipulator, however.)

    In the end, the printf format specifiers are about the same as
    integral or floating point literals. You don't want either in
    your code.

    > The real problem is that C++ does not have a native format
    > mechanism.


    Obviously, since formatting is independent of the language. As
    I said above, it depends on the high level semantics of the
    value. What would the native format of a double be? It just
    doesn't make sense.

    More generally, "formatting" is really a case where you need
    double dispatch, on both the type being output, and the type of
    stream it's being output to. You don't want to overcharge data
    types with knowledge of how they are formatted (for twenty
    different types of streams, binary and text). But of course,
    the stream itself shouldn't even know of the existance of your
    types.

    In this regard, the solution used in iostream is pretty clever;
    it leverages off the fact that the type being output doesn't
    really need to be dynamically resolved, and uses overloading for
    that.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Oct 14, 2008
    #10
    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. Jakob Bieling

    Q: operator void* or operator bool?

    Jakob Bieling, Mar 5, 2004, in forum: C++
    Replies:
    2
    Views:
    587
    Rob Williscroft
    Mar 5, 2004
  2. John Smith
    Replies:
    2
    Views:
    425
    Ivan Vecerina
    Oct 6, 2004
  3. Alex Vinokur
    Replies:
    4
    Views:
    3,054
    Peter Koch Larsen
    Nov 26, 2004
  4. Alex Vinokur
    Replies:
    3
    Views:
    5,030
    Jeff Schwab
    Mar 20, 2005
  5. Tim Clacy
    Replies:
    15
    Views:
    2,691
    Kanenas
    May 30, 2005
Loading...

Share This Page