'Aggregate reference member and temporary lifetime

Given this code sample, what are the rules regarding the lifetime of the temporary string being passed to S.

struct S
{
    // [1] S(const std::string& str) : str_{str} {}
    // [2] S(S&& other) : str_{std::move(other).str} {}

    const std::string& str_;
};

S a{"foo"}; // direct-initialization

auto b = S{"bar"}; // copy-initialization with rvalue

std::string foobar{"foobar"};
auto c = S{foobar}; // copy-initialization with lvalue

const std::string& baz = "baz";
auto d = S{baz}; // copy-initialization with lvalue-ref to temporary

According to the standard:

N4140 12.2 p5.1 (removed in N4296)

A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits.

N4296 12.6.2 p8

A temporary expression bound to a reference member in a mem-initializer is ill-formed.

So having a user defined constructor like [1] is definitively not what we want. It's even supposed to be ill-formed in the latest C++14 (or is it?) neither gcc nor clang warned about it.
Does it change with direct aggregate initialization? I looks like in that case, the temporary lifetime is extended.

Now regarding copy-initialization, Default move constructor and reference members states that [2] is implicitly generated. Given the fact that the move might be elided, does the same rule apply to the implicitly generated move constructor?

Which of a, b, c, d has a valid reference?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source