Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. Streaming into default-constructed object
Forum Update on Monday, May 27th 2025

Streaming into default-constructed object

Scheduled Pinned Locked Moved C++ Gurus
10 Posts 3 Posters 4.3k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    Asperamanca
    wrote on last edited by
    #1

    I want to create a static constant by streaming into a default-constructed object. However, the compiler cannot locate the streaming operator, although I provide it:

    @QMap<float, int>& operator<<(QMap<float, int>& map,
    const QPair<float, int>& data)
    {
    (void) map.insert(data.first, data.second);
    return map;
    }

    static const QMap<float, int> s_Map
    = QMap<float, int>() << QPair<float,int>(1.0,0);@

    For contrast, the following code compiles ("works" would be too strong a word)

    @QMap<float, int>& operator<<(QMap<float, int>& map,
    const QPair<float, int>& data)
    {
    (void) map.insert(data.first, data.second);
    return map;
    }

    // Intermediate variable
    static QMap<float, int> s_tempMap;

    static const QMap<float, int> s_Map
    = s_tempMap << QPair<float,int>(1.0,0);@

    Why doesn't the first version compile?

    I'm using the MinGW provided with Qt 4.8 (4.4.0)

    EDIT:
    Completely forgot to post the error message:
    error: no match for 'operator<<' in 'QMap<float, int>() << QPair<float, int>(((const float&)((const float*)(&1.0e+0f))), ((const int&)((const int*)(&0))))'
    candidates are: QMap<float, int>& operator<<(QMap<float, int>&, const QPair<float, int>&)

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,
      You could do something like this

      @class FloatIntMap : public QMap<float, int>
      {
      public:
      FloatIntMap() :
      QMap<float, int>()
      {}

      inline FloatIntMap& operator <<(const QPair<float, int>& data)
      {
          insert(data.first, data.second);
          return *this;
      }
      

      };@

      Hope it helps

      EDIT
      Letting my code but removed my suggestion to avoid mistakes for other forum members.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • L Offline
        L Offline
        lgeyer
        wrote on last edited by
        #3

        The temporary <code>QMap<float, int>()</code> is an r-value, whereas <code>QMap<float, int>& operator<<(QMap<float, int>& map, const QPair<float, int>& data)</code> expects an l-value as its first parameter. The solution with the intermedia variable works as <code>static QMap<float, int> s_tempMap</code> is an l-value.

        1 Reply Last reply
        0
        • A Offline
          A Offline
          Asperamanca
          wrote on last edited by
          #4

          Isn't QMap<float, int>() just a default-constructed map? I've had this construct work in other cases.

          1 Reply Last reply
          0
          • L Offline
            L Offline
            lgeyer
            wrote on last edited by
            #5

            It indeed is, but it is still an r-value ;-)

            Each expression in C++ is either an l-value or an "r-value":http://thbecker.net/articles/rvalue_references/section_01.html, regardless of its type; and you cannot bind an r-value to a non-const reference - which you do by passing the temporary to operator<<().

            You either add an operator<< taking an r-value reference <code>QMap<float, int>&& map</code> make the first parameter a const reference <code>const QMap<float, int>& map</code> so you can bind an r-value to it, which makes no sense at all, as the map is const then and cannot be modified or you convert your r-value to an l-value by either giving it a name <code>static QMap<float, int> s_tempMap</code> or use an initialization function
            @
            QMap<float, int> initializeMap()
            {
            QMap<float, int> map;
            map << QPair<float, int>(1.0, 0);

            return map;
            

            }

            static const QMap<float, int> s_Map = initializeMap();
            @

            If you want to do it "right" upgrade to Qt5 dev, which has "initializer lists":http://www.stroustrup.com/C++11FAQ.html#init-list for the associative containers like QMap.

            1 Reply Last reply
            0
            • A Offline
              A Offline
              Asperamanca
              wrote on last edited by
              #6

              You have led me to an evil idea. How ugly is this:

              @
              // Regular operator for l-values
              QMap<float, int>& operator<<(QMap<float, int>& map,
              const QPair<float, int>& data)
              {
              (void) map.insert(data.first, data.second);
              return map;
              }

              // Operator for r-values. Creates a copy, appends and returns that
              QMap<float, int> operator<<(const QMap<float, int>& constMap,
              const QPair<float, int>& data)
              {
              QMap<float, int> map = constMap;
              (void) map.insert(data.first, data.second);
              return map;
              }

              // Now this compiles
              static const QMap<float, int> s_Map
              = QMap<float, int>() << QPair<float,int>(1.0,0);
              @

              Qt5 is, unfortunately, not an option.

              1 Reply Last reply
              0
              • L Offline
                L Offline
                lgeyer
                wrote on last edited by
                #7

                Well, it is as ugly as it more or less strips the const information of your QMap, as people are now allowed to write code like <code>s_Map << QPair<float, int>(2.0, 0)</code> without generating a compiler error (and not modifying the object either).

                1 Reply Last reply
                0
                • A Offline
                  A Offline
                  Asperamanca
                  wrote on last edited by
                  #8

                  I've decided to use your 2nd suggestion, initialization methods.
                  Thanks!

                  1 Reply Last reply
                  0
                  • L Offline
                    L Offline
                    lgeyer
                    wrote on last edited by
                    #9

                    I think I would prefer initialization methods as well, as they clearly express what you want to do, initialize an object (and thanks to return value optimization they should save a copy constructor invocation as well).

                    Although Qt 4 does not have initializer list support for its containers GCC 4.4 does, which can be used to provide a generic initalization method which should work with any Qt container (or just add the respective constructors to the containers if modifying Qt itself is an option for you).
                    @
                    template <typename Container,
                    typename Value = typename Container::value_type>
                    Container initialize(std::initializer_list<Value> values)
                    {
                    Container container;
                    foreach (const Value &value, values)
                    container.append(value);

                    return container;
                    

                    }

                    template <typename Container,
                    typename Key = typename Container::key_type,
                    typename Value = typename Container::mapped_type>
                    Container initialize(std::initializer_list<QPair<Key, Value>> values)
                    {
                    Container container;
                    foreach (const Value &value, values)
                    container.insert(value.first, value.second);

                    return container;
                    

                    }

                    const QVector<int> s_Map1 = initialize<QVector<int>>({1, 2, 3});
                    const QVector<QPair<int, int>> s_Map2 = initialize<QVector<QPair<int, int>>>({{1,1},
                    {2,2},
                    {3,3}});
                    const QMap<float, int> s_Map3 = initialize<QMap<float, int>>({{1.0, 0},
                    {2.0, 0},
                    {3.0, 0}});
                    @

                    1 Reply Last reply
                    0
                    • A Offline
                      A Offline
                      Asperamanca
                      wrote on last edited by
                      #10

                      Cool stuff. Unfortunately, I'm stuck at C++2003 for the time being.

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved