Initializing std::basic_string<> with literals

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Dylan Nicholson

    Initializing std::basic_string<> with literals

    Been playing around with this all day, and haven't found a solution I
    like yet.

    Assuming some initial function:

    void foo(std::string & src)
    {
    src += "some fixed string";
    src += bar();
    src += "some other fixed string";
    src += bar2();
    src += "final fixed string";
    }

    What is the best way to turn this into a templated version that can
    work on both std::basic_stri ng<char> AND std::basic_stri ng<wchar_t>?

    Basically, I'd like something that looks (something) like:

    template <class T>
    void foo(std::basic_ string<T>& src)
    {
    src += CVT("some fixed string");
    src += bar();
    src += CVT("some other fixed string");
    src += bar2();
    src += CVT("final fixed string";
    }

    Where CVT is a macro that expands to either the plain string literal
    as is, or prepended with 'L' for the wchar_t version. Of course
    because macro expansion is done prior to template evaluation, this
    isn't directly possible.
    I've played around with various options, but most of them produce
    absurdly inefficient assembly-code (with various compilers), or just
    look plain ugly and don't really make doing the same sort of thing in
    the future any great deal easier.

    Anyway, any ideas people may have on alternative ways of achieving
    this effect are much appreciated!

    Dylan

    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
    [ comp.lang.c++.m oderated. First time posters: Do this! ]
  • Jeff Schwab

    #2
    Re: Initializing std::basic_stri ng&lt;&gt; with literals

    Dylan Nicholson wrote:[color=blue]
    > Been playing around with this all day, and haven't found a solution I
    > like yet.
    >
    > Assuming some initial function:
    >
    > void foo(std::string & src)
    > {
    > src += "some fixed string";
    > src += bar();
    > src += "some other fixed string";
    > src += bar2();
    > src += "final fixed string";
    > }
    >
    > What is the best way to turn this into a templated version that can
    > work on both std::basic_stri ng<char> AND std::basic_stri ng<wchar_t>?
    >
    > Basically, I'd like something that looks (something) like:
    >
    > template <class T>
    > void foo(std::basic_ string<T>& src)
    > {
    > src += CVT("some fixed string");
    > src += bar();
    > src += CVT("some other fixed string");
    > src += bar2();
    > src += CVT("final fixed string";
    > }
    >
    > Where CVT is a macro that expands to either the plain string literal
    > as is, or prepended with 'L' for the wchar_t version. Of course
    > because macro expansion is done prior to template evaluation, this
    > isn't directly possible.
    > I've played around with various options, but most of them produce
    > absurdly inefficient assembly-code (with various compilers), or just
    > look plain ugly and don't really make doing the same sort of thing in
    > the future any great deal easier.
    >
    > Anyway, any ideas people may have on alternative ways of achieving
    > this effect are much appreciated![/color]

    Would it be reasonable to specialize the template for each of "char" and
    "wchar_t"?

    Comment

    • Thomas Mang

      #3
      Re: Initializing std::basic_stri ng&lt;&gt; with literals



      Dylan Nicholson schrieb:
      [color=blue]
      > Been playing around with this all day, and haven't found a solution I
      > like yet.
      >
      > Assuming some initial function:
      >
      > void foo(std::string & src)
      > {
      > src += "some fixed string";
      > src += bar();
      > src += "some other fixed string";
      > src += bar2();
      > src += "final fixed string";
      > }
      >
      > What is the best way to turn this into a templated version that can
      > work on both std::basic_stri ng<char> AND std::basic_stri ng<wchar_t>?[/color]

      #include <string>

      char const* bar();
      wchar_t const* bar2();

      template <typename charT, class traitsT, class allocatorT>
      struct string_writer;

      template <class traitsT, class allocatorT>
      struct string_writer<c har, traitsT, allocatorT>
      {
      typedef std::basic_stri ng<char, traitsT, allocatorT> string_type;

      static void write_string(st ring_type& String)
      {
      String += "some fixed string";
      String += bar();
      String += "some other fixed string";
      String += "final fixed string";
      }
      };


      template <class traitsT, class allocatorT>
      struct string_writer<w char_t, traitsT, allocatorT>
      {
      typedef std::basic_stri ng<wchar_t, traitsT, allocatorT> string_type;

      static void write_string(st ring_type& String)
      {
      String += L"some fixed string";
      String += bar2();
      String += L"some other fixed string";
      String += L"final fixed string";
      }
      };


      template <typename charT, class traitsT, class allocatorT>
      void foo(std::basic_ string<charT, traitsT, allocatorT> & String)
      {
      string_writer<c harT, traitsT, allocatorT>::wr ite_string(Stri ng);
      }


      int main()
      {
      std::basic_stri ng<char> String1;
      foo(String1);

      std::basic_stri ng<wchar_t> String2;
      foo(String2);
      }



      Don't know if this is what you would call the 'best' solution, but it is
      a working one.


      regards,

      Thomas

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.m oderated. First time posters: Do this! ]

      Comment

      • Hendrik Schober

        #4
        Re: Initializing std::basic_stri ng&lt;&gt; with literals

        Dylan Nicholson <wizofaus@hotma il.com> wrote:[color=blue]
        > [...]
        > template <class T>
        > void foo(std::basic_ string<T>& src)
        > {
        > src += CVT("some fixed string");
        > src += bar();
        > src += CVT("some other fixed string");
        > src += bar2();
        > src += CVT("final fixed string";
        > }
        > [...]
        > Anyway, any ideas people may have on alternative ways of achieving
        > this effect are much appreciated![/color]

        Move your literals into a traits class
        that's templatized on 'T'. Then you are
        free to decide how you implement those.
        [color=blue]
        > Dylan[/color]

        Schobi

        --
        SpamTrap@gmx.de is never read
        I'm Schobi at suespammers dot org

        "Sometimes compilers are so much more reasonable than people."
        Scott Meyers



        [ See http://www.gotw.ca/resources/clcm.htm for info about ]
        [ comp.lang.c++.m oderated. First time posters: Do this! ]

        Comment

        • John Harrison

          #5
          Re: Initializing std::basic_stri ng&lt;&gt; with literals


          "Dylan Nicholson" <wizofaus@hotma il.com> wrote in message
          news:7d428a77.0 402122037.3669c 93b@posting.goo gle.com...[color=blue]
          > Been playing around with this all day, and haven't found a solution I
          > like yet.
          >
          > Assuming some initial function:
          >
          > void foo(std::string & src)
          > {
          > src += "some fixed string";
          > src += bar();
          > src += "some other fixed string";
          > src += bar2();
          > src += "final fixed string";
          > }
          >
          > What is the best way to turn this into a templated version that can
          > work on both std::basic_stri ng<char> AND std::basic_stri ng<wchar_t>?
          >
          > Basically, I'd like something that looks (something) like:
          >
          > template <class T>
          > void foo(std::basic_ string<T>& src)
          > {
          > src += CVT("some fixed string");
          > src += bar();
          > src += CVT("some other fixed string");
          > src += bar2();
          > src += CVT("final fixed string";
          > }
          >
          > Where CVT is a macro that expands to either the plain string literal
          > as is, or prepended with 'L' for the wchar_t version. Of course
          > because macro expansion is done prior to template evaluation, this
          > isn't directly possible.
          > I've played around with various options, but most of them produce
          > absurdly inefficient assembly-code (with various compilers), or just
          > look plain ugly and don't really make doing the same sort of thing in
          > the future any great deal easier.
          >
          > Anyway, any ideas people may have on alternative ways of achieving
          > this effect are much appreciated![/color]

          Perhaps this (untested)

          template <class C >
          std::basic_stri ng<C> CVT(const C* lit)
          {
          return lit;
          }

          john



          [ See http://www.gotw.ca/resources/clcm.htm for info about ]
          [ comp.lang.c++.m oderated. First time posters: Do this! ]

          Comment

          • Thomas Mang

            #6
            Re: Initializing std::basic_stri ng&lt;&gt; with literals



            Dylan Nicholson schrieb:
            [color=blue]
            > Been playing around with this all day, and haven't found a solution I
            > like yet.
            >
            > Assuming some initial function:
            >
            > void foo(std::string & src)
            > {
            > src += "some fixed string";
            > src += bar();
            > src += "some other fixed string";
            > src += bar2();
            > src += "final fixed string";
            > }
            >
            > What is the best way to turn this into a templated version that can
            > work on both std::basic_stri ng<char> AND std::basic_stri ng<wchar_t>?[/color]

            Another possible solution (maybe clearer than my previous one, because
            less code duplication):


            #include <cstring>
            #include <string>
            #include <algorithm>


            char const* bar();
            char const* bar2();


            template <typename charT, class traitsT, class allocatorT>
            struct string_converte r;


            template <class traitsT, class allocatorT>
            struct string_converte r<char, traitsT, allocatorT>
            {
            static std::basic_stri ng<char, traitsT, allocatorT> convert(char const*
            String)
            {
            return std::basic_stri ng<char, traitsT, allocatorT>(Str ing);
            }
            };


            template <class traitsT, class allocatorT>
            struct string_converte r<wchar_t, traitsT, allocatorT>
            {
            static std::basic_stri ng<wchar_t, traitsT, allocatorT> convert(char
            const* String)
            {
            std::basic_stri ng<wchar_t, traitsT, allocatorT> ReturnValue;

            std::size_t const StringLength(st d::strlen(Strin g));
            ReturnValue.res erve(StringLeng th);
            std::copy(Strin g, String + StringLength,
            std::back_inser ter(ReturnValue ));

            return ReturnValue;
            }
            };

            template <typename charT, class traitsT, class allocatorT>
            void foo(std::basic_ string<charT, traitsT, allocatorT>& src)
            {
            typedef string_converte r<charT, traitsT, allocatorT> sc;

            src += sc::convert("so me fixed string");
            src += sc::convert(bar ());
            src += sc::convert("so me other fixed string");
            src += sc::convert(bar 2());
            src += sc::convert("fi nal fixed string");
            }

            int main()
            {
            std::basic_stri ng<char> String1;
            foo(String1);

            std::basic_stri ng<wchar_t> String2;
            foo(String2);
            }


            hope this helps.


            regards,

            Thomas

            [ See http://www.gotw.ca/resources/clcm.htm for info about ]
            [ comp.lang.c++.m oderated. First time posters: Do this! ]

            Comment

            • Evan Carew

              #7
              Re: Initializing std::basic_stri ng&lt;&gt; with literals

              -----BEGIN PGP SIGNED MESSAGE-----
              Hash: SHA1

              Dylan,

              Unfortunately, C++'s string class doesn't support the operations of
              PERL's or JAVA's string class such as mystring += "Something new to
              add". In order to get this functionality in C++ you need to use one of
              the string stream calsses as an intermediary. An example would be:

              #include <strstream>

              ......

              ostrstream mybuf;
              mybuf << "Something new to add" << endl;
              mybuf << "some other fixed string" << endl;

              string returned_string = mybuf.str();


              Evan Carew

              Dylan Nicholson wrote:[color=blue]
              > Been playing around with this all day, and haven't found a solution I
              > like yet.
              >
              > Assuming some initial function:
              >
              > void foo(std::string & src)
              > {
              > src += "some fixed string";
              > src += bar();
              > src += "some other fixed string";
              > src += bar2();
              > src += "final fixed string";
              > }
              >[/color]
              -----BEGIN PGP SIGNATURE-----
              Version: GnuPG v1.0.6 (GNU/Linux)
              Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

              iD8DBQFALPOtoo/Prlj9GScRAuPoAJ 9Lr9B4UTpV39hXb bwUkQXBvSi95gCf QgDJ
              hmEFyZxsELgMUaq vmABsoRI=
              =3iZs
              -----END PGP SIGNATURE-----

              [ See http://www.gotw.ca/resources/clcm.htm for info about ]
              [ comp.lang.c++.m oderated. First time posters: Do this! ]

              Comment

              • Dylan Nicholson

                #8
                Re: Initializing std::basic_stri ng&lt;&gt; with literals

                Jeff Schwab <jeffplus@comca st.net> wrote in message news:<kuGdne4wc PCNTLHdRVn-uQ@comcast.com> ...[color=blue]
                > Dylan Nicholson wrote:[color=green]
                > > I've played around with various options, but most of them produce
                > > absurdly inefficient assembly-code (with various compilers), or just
                > > look plain ugly and don't really make doing the same sort of thing in
                > > the future any great deal easier.
                > >
                > > Anyway, any ideas people may have on alternative ways of achieving
                > > this effect are much appreciated![/color]
                >
                > Would it be reasonable to specialize the template for each of "char" and
                > "wchar_t"?[/color]

                Er, how would you avoid writing exactly the same code twice then?

                Actually I found a solution using a combination of macros and
                overloaded functions (didn't even use templates in the end!); the only
                drawback I found was that when used with single char literals it
                wouldn't allow me to use them as a constant expression (even though
                they clearly were). Of course on most platforms a char literal
                promotes to a wchar_t literal correctly by default, but not on AS/400,
                where char is EBCDIC and wchar_t is Unicode.

                Dylan

                Comment

                • Jeff Schwab

                  #9
                  Re: Initializing std::basic_stri ng&lt;&gt; with literals

                  Dylan Nicholson wrote:[color=blue]
                  > Jeff Schwab <jeffplus@comca st.net> wrote in message news:<kuGdne4wc PCNTLHdRVn-uQ@comcast.com> ...
                  >[color=green]
                  >>Dylan Nicholson wrote:
                  >>[color=darkred]
                  >>>I've played around with various options, but most of them produce
                  >>>absurdly inefficient assembly-code (with various compilers), or just
                  >>>look plain ugly and don't really make doing the same sort of thing in
                  >>>the future any great deal easier.
                  >>>
                  >>>Anyway, any ideas people may have on alternative ways of achieving
                  >>>this effect are much appreciated![/color]
                  >>
                  >>Would it be reasonable to specialize the template for each of "char" and
                  >>"wchar_t"?[/color]
                  >
                  >
                  > Er, how would you avoid writing exactly the same code twice then?[/color]

                  If it's the same code, why are you writing it twice? It's different
                  (though similar) code.
                  [color=blue]
                  > Actually I found a solution using a combination of macros and
                  > overloaded functions (didn't even use templates in the end!);[/color]

                  Mazel tov.
                  [color=blue]
                  > the only
                  > drawback I found was that when used with single char literals it
                  > wouldn't allow me to use them as a constant expression (even though
                  > they clearly were). Of course on most platforms a char literal
                  > promotes to a wchar_t literal correctly by default, but not on AS/400,
                  > where char is EBCDIC and wchar_t is Unicode.[/color]

                  Hm. I wonder whether you still would have that problem if you weren't
                  circumventing the type system.

                  Comment

                  • Maciej Sobczak

                    #10
                    Re: Initializing std::basic_stri ng&lt;&gt; with literals

                    Hi,

                    Dylan Nicholson wrote:
                    [color=blue]
                    > Been playing around with this all day, and haven't found a solution I
                    > like yet.[/color]

                    I'm not sure whether this is OK (my two compilers I have access to right
                    at the moment cannot eat this stuff), but let's try:

                    template <class charT>
                    const charT *
                    typedLiteral(co nst char *str, const wchar_t *wstr);

                    template <>
                    const char *
                    typedLiteral<ch ar>(const char *str, const wchar_t *wstr)
                    {
                    return str;
                    }

                    template <>
                    const wchar_t *
                    typedLiteral<wc har_t>(const char *str, const wchar_t *wstr)
                    {
                    return wstr;
                    }

                    #define CVT(type, str) typedLiteral<ty pe>(str, L##str)

                    template <class T>
                    void foo(std::basic_ string<T> & src)
                    {
                    src += CVT(T, "hello");
                    src += CVT(T, " world!");
                    }

                    The CVT macro should be used only with literals, duplicating them and
                    adding L in front of one of them. Later, the typedLiteral template
                    selects the one that is really needed.


                    --
                    Maciej Sobczak : http://www.msobczak.com/
                    Programming : http://www.msobczak.com/prog/


                    [ See http://www.gotw.ca/resources/clcm.htm for info about ]
                    [ comp.lang.c++.m oderated. First time posters: Do this! ]

                    Comment

                    • Thomas Mang

                      #11
                      Re: Initializing std::basic_stri ng&lt;&gt; with literals



                      Evan Carew schrieb:
                      [color=blue]
                      >
                      > Unfortunately, C++'s string class doesn't support the operations of
                      > PERL's or JAVA's string class such as mystring += "Something new to
                      > add".[/color]

                      Huhh?
                      Where did you get this from?

                      std::basic_stri ng provides a whole bunch of overloaded operators, including
                      overloads of operator += (as member function) and other operators (such as
                      + and comparison) as namespace-scope functions.

                      See 21.3.5.1 and 21.3.7.


                      regards,

                      Thomas

                      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
                      [ comp.lang.c++.m oderated. First time posters: Do this! ]

                      Comment

                      • Evan Carew

                        #12
                        Re: Initializing std::basic_stri ng&lt;&gt; with literals

                        -----BEGIN PGP SIGNED MESSAGE-----
                        Hash: SHA1

                        Tom,

                        Seems you are right. I don't know where I got that idea. Perhaps the
                        earlier versions of string were invariants.

                        Evan

                        Thomas Mang wrote:[color=blue]
                        > Evan Carew schrieb:
                        >
                        >[color=green]
                        >>Unfortunately , C++'s string class doesn't support the operations of
                        >>PERL's or JAVA's string class such as mystring += "Something new to
                        >>add".[/color]
                        >
                        >
                        > Huhh?
                        > Where did you get this from?
                        >
                        > std::basic_stri ng provides a whole bunch of overloaded operators, including
                        > overloads of operator += (as member function) and other operators (such as
                        > + and comparison) as namespace-scope functions.
                        >
                        > See 21.3.5.1 and 21.3.7.
                        >
                        >
                        > regards,
                        >
                        > Thomas
                        >[/color]
                        -----BEGIN PGP SIGNATURE-----
                        Version: GnuPG v1.0.6 (GNU/Linux)
                        Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

                        iD8DBQFALpv+oo/Prlj9GScRAmFKAJ 9eky/P7WpupAcDIlZ9Av On62JtawCeNeF+
                        N91Kjer/LTgYopGw4V/q0x8=
                        =t7Ps
                        -----END PGP SIGNATURE-----

                        [ See http://www.gotw.ca/resources/clcm.htm for info about ]
                        [ comp.lang.c++.m oderated. First time posters: Do this! ]

                        Comment

                        • Dylan Nicholson

                          #13
                          Re: Initializing std::basic_stri ng&lt;&gt; with literals

                          Maciej Sobczak <no.spam@no.spa m.com> wrote in message news:<c0iuut$ln n$1@atlantis.ne ws.tpi.pl>...[color=blue]
                          > Hi,
                          >
                          >
                          > The CVT macro should be used only with literals, duplicating them and
                          > adding L in front of one of them. Later, the typedLiteral template
                          > selects the one that is really needed.[/color]

                          That's roughly what I did in the end, but as I need to support VC 6
                          which can't select template specializations with all the same argument
                          signatures, I passed in a dummy parameter, and didn't even bother
                          making them templates.
                          I'm just hoping that now it doesn't turn out that I actually need to
                          do it at runtime (eg using wcstombs) in order to control how the
                          conversion is done.

                          Dylan

                          [ See http://www.gotw.ca/resources/clcm.htm for info about ]
                          [ comp.lang.c++.m oderated. First time posters: Do this! ]

                          Comment

                          • Steve Haigh

                            #14
                            Re: Initializing std::basic_stri ng&lt;&gt; with literals

                            [color=blue]
                            > Seems you are right. I don't know where I got that idea. Perhaps the
                            > earlier versions of string were invariants.
                            >[/color]
                            I don't think so. In Java strings are immutable, perhaps this is the
                            source of the confusion?

                            BTW, it makes it a lot easier for others to follow up to posts if you
                            don't top-post.


                            [ See http://www.gotw.ca/resources/clcm.htm for info about ]
                            [ comp.lang.c++.m oderated. First time posters: Do this! ]

                            Comment

                            • Brian McKeever

                              #15
                              Re: Initializing std::basic_stri ng&lt;&gt; with literals

                              Evan Carew <tempcarew@pobo x.com> wrote in message[color=blue]
                              > Unfortunately, C++'s string class doesn't support the operations of
                              > PERL's or JAVA's string class such as mystring += "Something new to
                              > add". In order to get this functionality in C++ you need to use one of
                              > the string stream calsses as an intermediary. An example would be:[/color]

                              As Thomas Mang pointed out, std::string does support operators + and
                              +=. I think you've reversed Java and C++ in your head. Java supports
                              the 'string1 += "foo";' syntax, but the compiler translates this into
                              the equivalent of your suggested code:
                              [color=blue]
                              > ostrstream mybuf;
                              > mybuf << "Something new to add" << endl;
                              > mybuf << "some other fixed string" << endl;[/color]

                              Brian

                              [ See http://www.gotw.ca/resources/clcm.htm for info about ]
                              [ comp.lang.c++.m oderated. First time posters: Do this! ]

                              Comment

                              Working...