操作中的显式ref-qualified转换操作符模板 [英] Explicit ref-qualified conversion operator templates in action
问题描述
给定以下转换运算符
struct A
{
template< typename T&显式运算符T& ()&&;
template< typename T>显式运算符T& ()& ;;
template< typename T>显式运算符const T& ()const& ;;
};
struct B {};
我希望以下转换全部有效,但有些给出编译错误( live example ):
A a;
A&& ar = std :: move(a);
A& al = a;
const A& ac = a;
B&& bm(std :: move(a)); // 1. OK
B&& bt(A {}); // 2. OK
B&& br(ar); // 3.错误:没有从A到B的可行转换
B& bl(a1); // 4. OK
const B& bz(a1); // 5. OK
const B& bc(ac); // 6. OK
B cm(std :: move(a)); // 7.错误:调用B的构造函数b ambiguous
B ct(A {}); // 8. error:调用B的构造函数b ambiguous
B cr(ar); // 9. OK
特别是,1似乎与3相同,
任何解释或解决方法?
动机是又一个任何,我最终必须使所有转换操作符显式 std :: is_constructible
, std :: is_convertible
可以避免类型trait的问题,
EDIT 2 。只要注意到
B cm = std :: move(a);
B ct = A {};如果转换操作符不显式
,则
< >。所以这是显式
进来:最初我的样本使用复制初始化,当我切换到显式
使用直接初始化。
>
B cm(std :: move ); // 7.错误:调用B的构造函数b ambiguous
B ct(A {}); // 8.错误:调用B的构造函数b ambiguous
这两种情况是一样的:对于类型A的rvalue参数。
直接初始化的候选函数都是构造函数,在这种情况下,复制构造函数 B :: B (const B&)
和移动构造函数 B(B&&)
是可行的,因为存在从右值A到 const B&
和 B&&
。过载分辨率无法在这两个构造函数之间进行决定,因为调用任一个都需要将用户定义的转换直接转换为参数类型,并且用户定义的转换序列仅按第二个标准转换进行排序:
13.3.3.2/3 [over.ics.rank]
:用户定义的转换序列U1是比另一个用户定义的转换序列U2更好的转换序列,如果它们包含相同的用户定义的转换函数...并且U1的第二标准转换序列比U2的第二标准转换序列更好。
这不同于调用具有&&和const& -qualified重载的成员函数,因为在这种情况下,重载解决是排名标准转换序列S1是比标准转换序列S2更好的转换序列,如果S1是标准转换序列S2,则标准转换序列S1是比标准转换序列S2更好的转换序列。和S2是引用绑定(8.5.3),并且不是指没有ref-qualifier声明的非静态成员函数的隐式对象参数,S1将右值引用绑定到右值,而S2绑定左值引用。 p>
Given the following conversion operators
struct A
{
template<typename T> explicit operator T&& () &&;
template<typename T> explicit operator T& () &;
template<typename T> explicit operator const T& () const&;
};
struct B {};
I would expect the following conversions to be all valid, yet some give compile errors (live example):
A a;
A&& ar = std::move(a);
A& al = a;
const A& ac = a;
B&& bm(std::move(a)); // 1. OK
B&& bt(A{}); // 2. OK
B&& br(ar); // 3. error: no viable conversion from A to B
B& bl(al); // 4. OK
const B& bz(al); // 5. OK
const B& bc(ac); // 6. OK
B cm(std::move(a)); // 7. error: call to constructor of B ambiguous
B ct(A{}); // 8. error: call to constructor of B ambiguous
B cr(ar); // 9. OK
In particular, 1 appears to be identical to 3, and almost identical to 2 (similarly for 7 to 9, 8), yet behave differently.
Any explanation or workaround?
My motivation is Yet another 'any', where I eventually had to make all conversion operators explicit
to avoid problems with type traits like std::is_constructible
, std::is_convertible
, then I bumped into new problems.
EDIT Sorry, please ignore 3 and 9, my mistake (thanks Kerrek SB). Yet 7 and 8 remain as problems. Also, explicit
appears to be irrelevant after all, sorry again.
EDIT 2 Just noticed that
B cm = std::move(a);
B ct = A{};
are valid if the conversion operators are not explicit
. So that's where explicit
comes in: initially my samples used copy-initialization, and when I switched to explicit
I had to use direct-initialization. Then this problem came up (cases 7 and 8).
Yet 7 and 8 remain as problems
B cm(std::move(a)); // 7. error: call to constructor of B ambiguous
B ct(A{}); // 8. error: call to constructor of B ambiguous
The two cases are the same: direct initialization with rvalue argument of type A.
The candidate functions for direct initialization are all constructors, and in this case, both copy constructor B::B(const B&)
and move constructor B(B&&)
are viable, since there is an implicit conversion from rvalue A to both const B&
and to B&&
. Overload resolution cannot decide between these two constructors because calling either one requires a user-defined conversion directly into the parameter type, and user-defined conversion sequences are only ranked by the second standard conversion:
13.3.3.2/3[over.ics.rank]
: User-defined conversion sequence U1 is a better conversion sequence than another user-defined conversion sequence U2 if they contain the same user-defined conversion function ... and the second standard conversion sequence of U1 is better than the second standard conversion sequence of U2."
This is different from calling a member function that has both && and const &-qualified overloads because in that case, overload resolution is ranking the reference bindings from rvalue argument to implict object parameter accoring to
Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if S1 and S2 are reference bindings (8.5.3) and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier, and S1 binds an rvalue reference to an rvalue and S2 binds an lvalue reference.
这篇关于操作中的显式ref-qualified转换操作符模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!