Skip to content

Conversation

teruyamato0731
Copy link
Contributor

Summary

This PR updates fmt::join and its underlying tuple_join_view to accept rvalue tuples. This enhances usability and fixes a critical lifetime issue, particularly when using fmt::join within format_as specializations.

The Problem

Currently, fmt::join only accepts an lvalue reference to a tuple. This prevents passing a temporary tuple, such as one returned from std::make_tuple or std::tie, directly to the function.

This limitation is particularly dangerous when implementing a format_as overload. For example:

struct SocketAddr {
  std::string addr;
  int port;
};

// This is unsafe with the current implementation.
auto format_as(const SocketAddr& s) {
  // std::tie returns a temporary (rvalue) tuple of references.
  return fmt::join(std::tie(s.addr, s.port), ":");
}

In the code above, the tuple_join_view returned by fmt::join holds a dangling reference to the temporary tuple created by std::tie, which is destroyed at the end of the format_as function. This leads to undefined behavior when the view is later used for formatting.

The Solution

This PR resolves the issue by changing fmt::join to accept tuples via a forwarding reference (T&&).

  • If an lvalue tuple is passed, it stores a reference as before.
  • If an rvalue tuple is passed, it is moved or copied into the tuple_join_view, extending its lifetime and preventing dangling references.

With this change, the format_as implementation shown above becomes safe and works as intuitively expected. This makes fmt::join a much more powerful and safe tool for creating custom formatters for aggregate types.

@teruyamato0731 teruyamato0731 marked this pull request as ready for review October 1, 2025 17:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant