运行中明确的ref-qualified转换运算符模板

时间:2014-04-30 00:29:37

标签: c++ c++11 rvalue-reference conversion-operator ref-qualifier

给出以下转换运算符

struct A
{
    template<typename T> explicit operator T&&       () &&;
    template<typename T> explicit operator T&        () &;
    template<typename T> explicit operator 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. 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),但表现不同。

任何解释或解决方法?

我的动机是Yet another 'any',我最终必须制作所有转换操作符explicit以避免类似std::is_constructiblestd::is_convertible等类型特征的问题,然后我遇到了新的问题问题。

编辑抱歉,请忽略3和9,我的错误(感谢Kerrek SB)。然而,7和8仍然是问题。此外,explicit似乎无关紧要,再次抱歉。

编辑2 刚刚注意到

B        cm = std::move(a);
B        ct = A{};
如果转换运算符不是explicit,则

有效。这就是explicit所在的地方:最初我的样本使用了复制初始化,当我切换到explicit时,我不得不使用直接初始化。 然后出现了这个问题(案例7和8)。

1 个答案:

答案 0 :(得分:4)

  

然而,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的rvalue参数直接初始化。

直接初始化的候选函数都是构造函数,在这种情况下,复制构造函数B::B(const B&)和移动构造函数B(B&&)都是可行的,因为存在从rvalue A到{{{}的隐式转换。 1}}和const B&。重载决策不能在这两个构造函数之间决定,因为调用其中一个需要用户定义的转换直接进入参数类型,而用户定义的转换序列仅按第二个标准转换进行排序:

  

B&&:用户定义的转换序列U1是比另一个用户定义的转换序列U2更好的转换序列,如果它们包含相同的用户定义转换函数...并且U1的第二个标准转换序列是优于U2的第二个标准转换序列。&#34;

这与调用同时具有&amp;&amp;和&amp;和const&amp; -qualified重载,因为在这种情况下,重载决策将从rvalue参数到implict对象参数的引用绑定排序为

  

标准转换序列S1是比标准转换序列S2更好的转换序列,如果S1和S2是引用绑定(8.5.3)并且都没有引用没有ref-qualifier声明的非静态成员函数的隐式对象参数,并且S1将右值引用绑定到右值,S2绑定左值引用。