This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4319. Supporting copy-elision in function wrappers

Section: 22.10.4 [func.require] Status: New Submitter: Tomasz KamiƄski Opened: 2025-08-19 Last modified: 2025-08-23

Priority: Not Prioritized

View other active issues in [func.require].

View all other issues in [func.require].

View all issues with New status.

Discussion:

The wording for argument forwarding call wrappers in 22.10.4 [func.require] p3,

This forwarding step delivers rvalue arguments as rvalue references and lvalue arguments as lvalue references.

requires that each wrapper binds a temporary to rvalue reference (materializing it), and then pass that xvalue. This essentially codifies an implementation where wrappers provide an operator() that accepts Args&&.... This is fine for most of the wrappers.

For some wrappers more efficient implementation strategies are possible:

However, such implementation strategies are currently disallowed per 22.10.4 [func.require] p3, as invoking the function wrapper with a prvalue bind_front(f)(T()) requires a temporary to be materialized, and then moved into the parameter of f. For example:

struct M 
{
  M() { std::cout << "Default" < std::endl; }
  M(M&& m) { std::cout << "Move" < std::endl; }
};

struct F
{ 
  void operator()(M m) {} 
} f;

The call f(M{}) will print only "Default" but bind_front(f)(M{}) is required to produce "Default" and "Move". We should allow implementations to elide the move operations, but not require it.

The suggested changes by this issue have been implemented in libstdc++ for bind_front/bind_back.

Proposed resolution:

This wording is relative to N5014.

  1. Modify 22.10.4 [func.require] as indicated:

    -3- Every call wrapper (22.10.3 [func.def]) meets the Cpp17MoveConstructible and Cpp17Destructible requirements. An argument forwarding call wrapper is a call wrapper that can be called with an arbitrary argument list and delivers the arguments to the target object as references. This forwarding step delivers rvalue arguments as rvalue references and lvalue arguments as lvalue references.:

    1. (3.?) — lvalue arguments as lvalues,

    2. (3.?) — xvalue arguments as xvalues,

    3. (3.?) — prvalue arguments as either prvalues or xvalues.