Operator...

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • martyn_dobson@hotmail.com

    Operator...

    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.
  • Victor Bazarov

    #2
    Re: Operator...

    martyn_dobson@h otmail.com 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);
    }
    >
    >
    >
    just a quick thought,
    Well, on the first glance it looked OK, but then I thought, so why can't
    you just do

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

    ? It would accomplish the exactly same thing without changing the
    language. Do you think you could give an example that couldn't be
    countered by a use of a static_cast<or a member function that already
    exists?

    Generally speaking, you're promoting the lowest rank conversion operator
    which can be used when no other standard or user-defined conversion is
    suitable, I am guessing. Since I don't use conversions that much I
    can't really immediately see where else (aside from the actual '...') it
    would be useful.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask

    Comment

    • martyn_dobson@hotmail.com

      #3
      Re: Operator...

      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.

      Comment

      • Juha Nieminen

        #4
        Re: Operator...

        martyn_dobson@h otmail.com 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.

        Comment

        • Victor Bazarov

          #5
          Re: Operator...

          martyn_dobson@h otmail.com wrote:
          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.
          The problem with "handy little" additions like that is that they aren't
          as little as you might think. It's not always easy to find the right
          balance, it seems. If you only say that 'operator...' is used where the
          object is passed to the function with variable number of arguments, then
          the usefulness of that addition is really questionable. If you try to
          extend the scope of the change to, say, include any possible conversion
          that is not otherwise explicitly specified, then all the potential areas
          that the change is going to affect suddenly become hard to enumerate.

          I would say that at this point on C++ development as a language, it is
          unlikely that such a narrowly scoped addition is going to be adopted.
          OTOH, it would be nice, perhaps, to amend the language to actually
          specify what conversion is going to be used when an object or a
          reference to an object is passed to the function with ellipsis, instead
          of just saying essentially nothing (by hiding behind UB excuse).

          Post to comp.lang.c++.m oderated (and write it up a bit more
          specifically), see what reaction you get. Some folks do not read the
          non-moderated forum (why, beats me), and you might actually want their
          input.

          V
          --
          Please remove capital 'A's when replying by e-mail
          I do not respond to top-posted replies, please don't ask

          Comment

          • Maxim Yegorushkin

            #6
            Re: Operator...

            On Oct 13, 11:10 am, martyn_dob...@h otmail.com 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~(TmpBu f const& buf)
            {
            return buf.format_arg;
            }

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

            struct X
            {
            StarString format(StarStri ng 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

            Comment

            • Jeff Schwab

              #7
              Re: Operator...

              martyn_dobson@h otmail.com 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 variadic templates in C++0x should provide the same benefit, but in
              a more generic way. They use the ... syntax. If you're comfortable
              with templates, I think you've got your wish.



              Comment

              • Ioannis Vranos

                #8
                Re: Operator...

                Maxim Yegorushkin wrote:
                >
                [...]
                >
                struct X
                {
                StarString format(StarStri ng s) const
                {
                s.n = snprintf(s.p, s.n, "X@%p", this);

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

                Comment

                • Maxim Yegorushkin

                  #9
                  Re: Operator...

                  On Oct 13, 7:02 pm, Ioannis Vranos <ivra...@no.spa m.nospamfreemai l.gr>
                  wrote:
                  Maxim Yegorushkin wrote:
                  >
                      [...]
                  >
                      struct X
                      {
                          StarString format(StarStri ng 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

                  Comment

                  • Juha Nieminen

                    #10
                    Re: Operator...

                    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<typena me 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.

                    Comment

                    • Maxim Yegorushkin

                      #11
                      Re: Operator...

                      On Oct 14, 1:15 pm, Juha Nieminen <nos...@thanks. invalidwrote:
                      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<typena me 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::ostream is just a type safety hack over snprintf() and
                      boost::format is another hack over std::ostream. 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

                      Comment

                      • Juha Nieminen

                        #12
                        Re: Operator...

                        Maxim Yegorushkin wrote:
                        The real problem is that C++ does not have a native format mechanism.
                        std::ostream 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::ostream. 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.

                        Comment

                        • James Kanze

                          #13
                          Re: Operator...

                          On Oct 14, 3:13 pm, Maxim Yegorushkin <maxim.yegorush ...@gmail.com>
                          wrote:
                          On Oct 14, 1:15 pm, Juha Nieminen <nos...@thanks. invalidwrote:
                          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<typena me 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:james.kan ze@gmail.com
                          Conseils en informatique orientée objet/
                          Beratung in objektorientier ter Datenverarbeitu ng
                          9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

                          Comment

                          • Paavo Helde

                            #14
                            Re: Operator...

                            martyn_dobson@h otmail.com kirjutas:
                            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);
                            }
                            As the problem with the ellipses is that one cannot pass through non-POD
                            objects, such an operator would presumably be just a "POD converter".
                            However, there are more than one way to convert something into a POD:
                            e.g. s.c_str(), &s, s.length(), s.empty(), etc. What you appear to want
                            is an operator converting a non-POD object into a POD object, which could
                            be passed to an ellipsis function expecting the arguments to follow the
                            printf() format syntax, for a specific format specifier, e.g. "%s". (Note
                            that if you had used "%p" instead there would have been a good chance the
                            code would have worked as (maybe) expected!)

                            This all seems very convoluted. For starters, the printf() function is
                            not implemented in the language proper (only in the library), but you are
                            advocating adding a feature for that in the language core. Second, the
                            ellipses may be used by other functions which are not printf-like.

                            So I would suggest to abandon that idea and simply just raise the
                            compiler warning level so it would warn you about passing non-POD-s
                            through the ellipses.

                            Regards
                            Paavo

                            Comment

                            Working...