以下代码:
using input_t = std::tuple<short, int&, const long&, const double>;
int b = 1;
int c = 2;
input_t t{0, b, c, 3};
在clang 9.0
中编译失败,但在gcc 9.2
中编译成功:https://godbolt.org/z/6CuEaf
clang
将失败,错误为:
In file included from <source>:2:
tuple:133:17: error: reference member '_M_head_impl' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object
: _M_head_impl(std::forward<_UHead>(__h)) { }
^~~~~~~~~~~~~~~~~~~~~~~~~
/tuple:218:4: note: in instantiation of function template specialization 'std::_Head_base<2, const long &, false>::_Head_base<int &>' requested here
_Base(std::forward<_UHead>(__head)) { }
^
/tuple:217:4: note: in instantiation of function template specialization 'std::_Tuple_impl<2, const long &, const double>::_Tuple_impl<int &, int, void>' requested here
: _Inherited(std::forward<_UTail>(__tail)...),
^
/tuple:217:4: note: in instantiation of function template specialization 'std::_Tuple_impl<1, int &, const long &, const double>::_Tuple_impl<int &, int &, int, void>' requested here
/tuple:627:11: note: in instantiation of function template specialization 'std::_Tuple_impl<0, short, int &, const long &, const double>::_Tuple_impl<int, int &, int &, int, void>' requested here
: _Inherited(std::forward<_UElements>(__elements)...) { }
^
<source>:10:13: note: in instantiation of function template specialization 'std::tuple<short, int &, const long &, const double>::tuple<int, int &, int &, int, true>' requested here
input_t t{0, b, c, 3};
^
这里哪一个是正确的?我看不到任何会导致超过b
和c
寿命的东西。
考虑以下代码:
struct X
{
X(int i)
{
std::cerr << "constructed from " << i << std::endl;
}
~X() { std::cerr << "destructedn"; }
};
struct Y
{
const X& ref_;
Y(const X& ref) : ref_(ref)
{
std::cerr << &ref << std::endl;
}
};
int main ()
{
int i = 1;
Y y(i);
std::cerr << &y.ref_ << std::endl;
}
其输出如下:
constructed from 1
0x7fff6a0bb78b
destructed
0x7fff6a0bb78b
现场演示在这里。
它在这里用Y
模拟了std::tuple
。在Y y(i)
中,参数ref
被绑定到类型为X
的临时。但随着ref
参数的使用寿命的结束,该临时性被破坏。然后,ref_
就变成了一个悬空引用,正如@rafix07在一条评论中指出的那样。
因此,以导致绑定到临时的方式初始化引用类型的元组成员是没有意义的。问题是是否需要编译器在这里发布诊断。我认为这不是必须的,而且我在[tuple]中没有看到任何相关信息。
它只是说,关于forward_as_tuple
:
构造一个引用
t
中参数的元组,该元组适合作为参数转发到函数由于结果可能包含对临时对象的引用,程序应确保此函数的返回值不会超过其任何参数的有效期。
但tuple
("直接"(构造函数的定义中没有相同的措辞。