用对tuple的引用初始化引用的元组

Initialize tuple of references with reference to tuple

本文关键字:引用 元组 初始化 tuple 用对      更新时间:2023-10-16

如果我有代码

#include <tuple>
using Vec3 = std::tuple<float, float, float>;
using Vec3Ref = std::tuple<float&, float&, float&>;
void stuff ()
{
  Vec3 foo (0,0,0);
  Vec3Ref bar (foo);
}

我得到错误

/usr/include/c++/4.6/tuple:100:4: error: binding of reference to type 'float' to
a value of type 'const float' drops qualifiers
: _M_head_impl(std::forward<_UHead>(__h)) { }
^ ~~~~~~~~~~~~~~~~~~~~~~~~~
//snip...
/usr/include/c++/4.6/tuple:257:11: note: in instantiation of function template
specialization 'std::_Tuple_impl<0, float &, float &, float &>::_Tuple_impl
<float, float, float>' requested here
: _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in))
^
18 : note: in instantiation of function template specialization
'std::tuple::tuple' requested here
Vec3Ref bar (foo);
^

我发现最接近的事情是这个问题,但问题似乎是关于初始化从std::make_tuple返回的元组,这是一个右值。然而,foo在很大程度上是左值。为什么这不起作用?这和使用std::tie有什么不同?

Github draft from 2014-07-23, [tuple.cnstr]

template <class... UType> constexpr tuple(tuple<UTypes...>&& u);

18要求: sizeof...(Types) == sizeof...(UTypes)is_constructible<Ti, Ui&&>::valuetrue的所有i

20备注:此构造函数不得参与重载解析,除非UTypes中的每个类型都是隐式的可转换为Types中的相应类型。

备注:部分定义了SFINAE。请注意,它与Requires:部分的不同之处在于,它要求使用is_convertible而不是is_constructible

在OP的示例中,这会导致检查is_convertible<float, float&>,该检查为false: float xvalue不能绑定到float lvalue引用:

is_convertible [meta.rel]/4

给定以下函数原型:

template <class T>
add_rvalue_reference_t<T>::type create() noexcept;

模板专门化is_convertible<From, To>的谓词条件必须满足,当且仅当下列条件是格式良好的,包括到函数返回类型的任何隐式转换:

To test() {
    return create<From>();
}

,

float& test() {
    return create<float>();
}

格式错误,create<float>()返回float&&,即xvalue。不能将结果绑定到左值引用。


众所周知,tuple的构建并不完善;参见例如提案N3680,它也处理了LWG缺陷2051。

然而,这些似乎都没有解决OP中的问题。