std::piecew..._construct_t(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

✨ std::piecewise_construct, std::piecewise_construct_t ✨

okay bestie, welcome to the C++ Standard Library page for std::piecewise_construct and std::piecewise_construct_t β€” the tag type + tag constant duo that lowkey fixes one specific ambiguity and then dips. it's a short page, it's a cute page, let's get into it πŸ’…


🌸 SYNOPSIS 🌸

these little guys live in the header <utility>:

struct piecewise_construct_t {
    explicit piecewise_construct_t() = default;
};

(1) (since C++11)

constexpr std::piecewise_construct_t piecewise_construct{};

(2) (since C++11) (until C++17)

inline constexpr std::piecewise_construct_t piecewise_construct{};

(since C++17)

so, breaking it down, no cap:

  1. std::piecewise_construct_t is an empty class tag type. its whole entire job is to disambiguate between different functions that take two tuple arguments. that's it. that's the gig. icon behavior honestly.
  2. the constant std::piecewise_construct is an instance of (1). a single, solitary, constexpr lil guy. πŸŽ€

now for the actual why, because this matters fr fr:

  • the overloads that do not use std::piecewise_construct_t assume that each tuple argument becomes the element of a pair.
  • the overloads that do use std::piecewise_construct_t assume that each tuple argument is used to construct, piecewise, a new object of specified type, which will become the element of the pair.

that's the whole vibe difference. one says "the tuple IS the element", the other says "the tuple is the ingredients list for the element". iykyk 🧚


πŸ¦‹ EXAMPLE πŸ¦‹

run this code, it's a good one:

#include <iostream>
#include <tuple>
#include <utility>

struct Foo
{
    Foo(std::tuple<int, float>)
    {
        std::cout << "Constructed a Foo from a tuple\n";
    }

    Foo(int, float)
    {
        std::cout << "Constructed a Foo from an int and a float\n";
    }
};

int main()
{
    std::tuple<int, float> t(1, 3.14);

    std::cout << "Creating p1...\n";
    std::pair<Foo, Foo> p1(t, t);

    std::cout << "Creating p2...\n";
    std::pair<Foo, Foo> p2(std::piecewise_construct, t, t);
}

πŸ’– Output

Creating p1...
Constructed a Foo from a tuple
Constructed a Foo from a tuple
Creating p2...
Constructed a Foo from an int and a float
Constructed a Foo from an int and a float

see how p1 slurped the tuple whole (constructor #1, twice), and p2 used std::piecewise_construct to say "no bestie, unpack it" and hit constructor #2 (twice)? that's the entire point of this thing. ate. πŸ”₯


🌈 Defect reports

the following behavior-changing defect reports were applied retroactively to previously published C++ standards. yes, they went back and fixed it. main character energy ✨

  • LWG 2510 β€” applied to C++11. behavior as published: the default constructor was non-explicit, which could lead to ambiguity. correct behavior: it's explicit now. πŸ™ˆ
ngl if you ever wonder why that constructor has explicit on it, this is the receipt. keep it explicit, bestie, for the love of everything.

πŸ‘‘ See also

  • constructor β€” constructs new pair (public member function of std::pair<T1,T2>)

that's the page!! go forth and disambiguate your tuple overloads, you gorgeous creature πŸ’œ

source: cppreference.com β€” http://cppreference.com Β· version/date: 2024.06.10 Β· std::piecew..._construct_t(3) 🫢⭐

πŸ“¦ where this page comes from