操作中的显式ref限定的转换运算符模板
Explicit ref-qualified conversion operator templates in action
给定以下转换运算符
struct A
{
template<typename T> explicit operator T&& () &&;
template<typename T> explicit operator T& () &;
template<typename T> explicit operator const T& () const&;
};
struct B {};
我希望以下转换都是有效的,但有些会出现编译错误(示例(:
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
特别地,1看起来与3相同,并且几乎与2相同(类似于7到9,8(,但是表现不同。
有什么解释或变通办法吗?
我的动机是另一个"任意",我最终不得不使所有转换运算符为explicit
,以避免std::is_constructible
、std::is_convertible
等类型特征的问题,然后我遇到了新的问题。
编辑对不起,请忽略3和9,我的错误(感谢Kerrek SB(。然而,7和8仍然是个问题。此外,explicit
似乎毕竟无关紧要,再次抱歉。
编辑2刚刚注意到
B cm = std::move(a);
B ct = A{};
如果转换运算符不是explicit
,则是有效的。这就是explicit
的作用所在:最初我的样本使用复制初始化,当我切换到explicit
时,我必须使用直接初始化然后这个问题出现了(案例7和8(。
然而7和8仍然是的问题
B cm(std::move(a)); // 7. error: call to constructor of B ambiguous
B ct(A{}); // 8. error: call to constructor of B ambiguous
这两种情况是相同的:使用A类型的右值参数进行直接初始化。
直接初始化的候选函数都是构造函数,在这种情况下,复制构造函数B::B(const B&)
和移动构造函数B(B&&)
都是可行的,因为存在从右值A到const B&
和B&&
的隐式转换。重载解析无法在这两个构造函数之间做出决定,因为调用其中任何一个都需要用户定义的直接转换为参数类型的转换,并且用户定义的转换序列仅按第二个标准转换进行排序:
13.3.3.2/3[over.ics.rank]
:如果用户定义的转换序列U1包含相同的用户定义转换函数,那么它们是比另一个用户定义转换序列U2更好的转换序列。。。U1的第二个标准转换序列比U2的第二标准转换序列好。">
这与调用同时具有&;以及const&-限定重载,因为在这种情况下,重载解析是根据对从右值参数到隐含对象参数的引用绑定进行排序
如果S1和S2是引用绑定(8.5.3(,并且都不引用在没有引用限定符的情况下声明的非静态成员函数的隐式对象参数,并且S1将右值引用绑定到右值,S2绑定左值引用,则标准转换序列S1是比标准转换序列S2更好的转换序列。
- 有没有一种方法可以通过"typedef"为重新定义的基本类型定义特征和强制转换运算符
- 构造函数和转换运算符之间的重载解析
- 分配给转换运算符失败-C++
- 转换运算符不适用于sleep_until
- 继承模板化转换运算符
- 模板转换运算符在 clang 6 和 clang 7 之间的区别
- 如何在模板化转换运算符中消除此构造的歧义?
- 为什么选择转换运算符的重载?
- 如何避免强制转换运算符 () 和访问运算符 [] 冲突?
- 如果可能的话,C++总是更喜欢右值引用转换运算符而不是常量左值引用吗?
- 了解转换运算符的选择C++
- 多个隐式转换运算符
- 这个typedef和转换运算符语法是什么意思
- 为什么转换运算符调用复制构造函数两次,而等效函数只调用它一次
- 类模板忽略了用户定义的转换运算符(非模板不忽略)
- 为什么在std::for_each()返回时调用转换运算符
- 为什么 std::optional 的强制转换运算符被忽略了
- 使用用户定义的转换运算符推导函数模板参数
- 模板转换运算符的分辨率不明确
- 统一初始化是隐式发生的,即使 int 强制转换运算符是使用 explicit 关键字声明的.原因是什么?