c++11tuplesuse-caseforwardingpiecewise

C++11 use-case for piecewise_construct of pair and tuple?


In N3059 I found the description of piecewise construction of pairs (and tuples) (and it is in the new Standard).

But I can not see when I should use it. I found discussions about emplace and non-copyable entities, but when I tried it out, I could not create a case where I need piecewiese_construct or could see a performance benefit.

Example. I thought I need a class which is non-copyable, but movebale (required for forwarding):

struct NoCopy {
  NoCopy(int, int) {};
  NoCopy(const NoCopy&) = delete; // no copy
  NoCopy& operator=(const NoCopy&) = delete; // no assign
  NoCopy(NoCopy&&) {}; // please move
  NoCopy& operator=(NoCopy&&) {}; // please move-assign
};

I then sort-of expected that standard pair-construction would fail:

pair<NoCopy,NoCopy> x{ NoCopy{1,2}, NoCopy{2,3} }; // fine!

but it did not. Actually, this is what I'd expected anyway, because "moving stuff around" rather then copying it everywhere in the stdlib, is it should be.

Thus, I see no reason why I should have done this, or so:

pair<NoCopy,NoCopy> y(
    piecewise_construct,
    forward_as_tuple(1,2),
    forward_as_tuple(2,3)
); // also fine

Solution

  • Not all types can be moved more efficiently than copied, and for some types it may make sense to even explicitly disable both copying and moving. Consider std::array<int, BIGNUM> as an an example of the former kind of a type.

    The point with the emplace functions and piecewise_construct is that such a class can be constructed in place, without needing to create temporary instances to be moved or copied.

    struct big {
        int data[100];
        big(int first, int second) : data{first, second} {
            // the rest of the array is presumably filled somehow as well
        }
    };
    
    std::pair<big, big> pair(piecewise_construct, {1,2}, {3,4});
    

    Compare the above to pair(big(1,2), big(3,4)) where two temporary big objects would have to be created and then copied - and moving does not help here at all! Similarly:

    std::vector<big> vec;
    vec.emplace_back(1,2);
    

    The main use case for piecewise constructing a pair is emplacing elements into a map or an unordered_map:

    std::map<int, big> map;
    map.emplace(std::piecewise_construct, /*key*/1, /*value*/{2,3});