std::tie(3)

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

πŸŽ€ std::tie(3) πŸŽ€

okay so bestie, welcome to the <tuple> section of the C++ Standard Library manual β€” this one's std::tie, and honestly? it's giving quiet-legend energy. ✨


🌸 NAME 🌸

std::tie β€” literally std::tie, that's the name, no notes πŸ’…


✨ Synopsis ✨

first things first, it lives in the header <tuple>, k?

Defined in header <tuple>
template< class... Types >                             (since C++11)
std::tuple<Types&...> tie( Types&... args ) noexcept;  (constexpr since C++14)

so what does it actually do? it creates a tuple of lvalue references to its arguments β€” or instances of std::ignore. that's the whole vibe. 🫢


πŸ¦‹ Parameters πŸ¦‹

  • args β€” zero or more lvalue arguments to construct the tuple from. yeah, zero is allowed, she's flexible like that. πŸ’–

🌈 Return value 🌈

a std::tuple object containing lvalue references. that's it, that's the return. πŸ‘‘


πŸ’œ Possible implementation πŸ’œ

here's how she might be implemented under the hood β€” no cap, it's kind of iconic how short it is:

template <typename... Args>
constexpr // since C++14
std::tuple<Args&...> tie(Args&... args) noexcept
{
    return {args...};
}

look at her. three lines. ate. πŸ”₯


πŸ“ Notes πŸ“

okay this is the good part: std::tie may be used to unpack a std::pair because std::tuple has a converting assignment from pairs:

bool result;
std::tie(std::ignore, result) = set.insert(value);

like, that's the whole trick. std::ignore holds the spot, result catches the bool. slay. πŸ’…


⭐ Example ⭐

two things to know going in, bestie:

  1. std::tie can be used to introduce lexicographical comparison to a struct or to unpack a tuple;
  2. std::tie can work with structured bindings: 🧚
// Run this code

#include <cassert>
#include <iostream>
#include <set>
#include <string>
#include <tuple>

struct S
{
    int n;
    std::string s;
    float d;

    friend bool operator<(const S& lhs, const S& rhs) noexcept
    {
        // compares lhs.n to rhs.n,
        // then lhs.s to rhs.s,
        // then lhs.d to rhs.d
        // in that order, first non-equal result is returned
        // or false if all elements are equal
        return std::tie(lhs.n, lhs.s, lhs.d) < std::tie(rhs.n, rhs.s, rhs.d);
    }
};

int main()
{
    // Lexicographical comparison demo:
    std::set<S> set_of_s;

    S value{42, "Test", 3.14};
    std::set<S>::iterator iter;
    bool is_inserted;

    // Unpack a pair:
    std::tie(iter, is_inserted) = set_of_s.insert(value);
    assert(is_inserted);

    // std::tie and structured bindings:
    auto position = [](int w) { return std::tuple(1 * w, 2 * w); };

    auto [x, y] = position(1);
    assert(x == 1 && y == 2);
    std::tie(x, y) = position(2); // reuse x, y with tie
    assert(x == 2 && y == 4);

    // Implicit conversions are permitted:
    std::tuple<char, short> coordinates(6, 9);
    std::tie(x, y) = coordinates;
    assert(x == 6 && y == 9);
}

the std::tie(lhs.n, lhs.s, lhs.d) < std::tie(rhs.n, rhs.s, rhs.d) line is the moment fr fr β€” lexicographical comparison in one line, no manual field-by-field pain. 😭πŸ”₯


🌸 See also 🌸

  • Structured binding (C++17) β€” binds the specified names to sub-objects or tuple elements of the initializer
  • make_tuple (C++11) β€” creates a tuple object of the type defined by the argument types (function template)
  • forward_as_tuple (C++11) β€” creates a tuple of forwarding references (function template)
  • tuple_cat (C++11) β€” creates a tuple by concatenating any number of tuples (function template)
  • ignore (C++11) β€” placeholder to skip an element when unpacking a tuple using tie (constant)

anyway that's the page!! πŸŽ€ source: http://cppreference.com, version 2024.06.10, and the page itself is std::tie(3) β€” go forth and unpack your pairs, bestie, iykyk πŸ’–βœ¨πŸ¦‹

πŸ“¦ where this page comes from