问题
If I have the code
#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);
}
I get the error
/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);
^
The closest thing I've found is this question, but the problem there seems to be about initializing with a tuple returned from std::make_tuple
, which is an rvalue. foo
, however, is very much an lvalue. Why does this not work? How is this different from using std::tie
?
回答1:
Github draft from 2014-07-23, [tuple.cnstr]
template <class... UType> constexpr tuple(tuple<UTypes...>&& u);
18Requires:
sizeof...(Types) == sizeof...(UTypes)
.is_constructible<Ti, Ui&&>::value
istrue
for all i.20Remark: This constructor shall not participate in overload resolution unless each type in
UTypes
is implicitly convertible to its corresponding type inTypes
.
The Remarks: section defines the SFINAE. Note how it's different from the Requires: section by requiring the use of is_convertible
instead of is_constructible
.
In the OP's example, this leads to the check is_convertible<float, float&>
, which is false: a float
xvalue cannot be bound to a float
lvalue reference:
is_convertible
[meta.rel]/4
Given the following function prototype:
template <class T> add_rvalue_reference_t<T>::type create() noexcept;
the predicate condition for a template specialization
is_convertible<From, To>
shall be satisfied if and only if the following vode would be well-formed, including any implicit conversions to the return type of the function:To test() { return create<From>(); }
Here,
float& test() {
return create<float>();
}
is ill-formed, create<float>()
returns a float&&
, that is, an xvalue. The result cannot be bound to an lvalue-reference.
It is well-known that the construction of tuple
is not perfect; see for example proposal N3680, which also addresses LWG defect 2051.
None of those seem to address the issue in the OP, however.
来源:https://stackoverflow.com/questions/24918426/initialize-tuple-of-references-with-reference-to-tuple