简体   繁体   中英

Why does std::map::const_iterator call the std::pair constructor during a std::for_each, but a simple for loop does not?

I have a slightly complex data member of a class, as noted in what follows:

class BranchOutputRow
{
...
}

class Foo
{

public:

    // Slightly complex data member here
    std::map<boost::multiprecision::cpp_int, std::set<BranchOutputRow>> hits;

    void DoLoop1()
    {
        // This loop calls the std::pair<> constructor

        std::for_each(hits.cbegin(), hits.cend(),
        [&](std::pair<boost::multiprecision::cpp_int,
                      std::set<BranchOutputRow>> const & hit)
        {
            ...
        }
    }

    void DoLoop2()
    {
        // This loop does NOT call the std::pair<> constructor

        for (std::map<boost::multiprecision::cpp_int,
                      std::set<BranchOutputRow>>::const_iterator hitsPtr 
                    = hits.cbegin();
         hitsPtr != hits.cend();
         ++hitsPtr)
         {
             ...            
         }
    }

}

int main()
{
    Foo foo;
    foo.hits[1] = std::set<BranchOutputRow>();
    foo.hits[1].insert(BranchOutputRow());

    foo.DoLoop1(); // direct access to map object is not available
    foo.DoLoop2(); // direct access to map object is available
}

As noted, I find that Loop #1 calls the std::pair constructor, despite the fact that the lambda function accepts its argument by reference. Therefore, in Loop 1, I do not have direct access to the object in the map, but only a copy. In my actual program, I need direct access; therefore, I must use the version indicated by Loop 2.

(In fact, Loop 2 does not call the std::pair constructor - not a surprise - and does provide direct access to the object in the map.)

I would think that std::for_each would have been carefully designed to provide the same semantics as a for loop such as Loop 2, and therefore not call the std::pair constructor, instead allowing direct access to the object in the map.

Why does Loop 1 call the std::pair constructor, despite the fact that the lambda function accepts its argument by reference?

The value_type of std::map<K,V> is std::pair<const K, V> . Your lambda takes std::pair<K,V> . Note the difference in constness.

The conversion is done through this constructor:

template< class U1, class U2 >
pair( const pair<U1, U2>& p );

(see (4) on this reference page )

The result of the conversion is a temporary, and temporaries can bind to const references, so your code works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM