在第一次尝试时,我忘记添加了explicit关键字并且收到错误.有人可以准确地解释为什么这个特定的错误发生了吗?我无法弄清事件的顺序.
#include <memory> template<typename T> struct shared_ptr : std::shared_ptr<T> { template<typename...Args> /*explicit*/ shared_ptr(Args &&... args) : std::shared_ptr<T>(std::forward<Args>(args)...) {} }; struct A {}; struct ConvertsToPtr { shared_ptr<A> ptr = shared_ptr<A>(new A()); operator shared_ptr<A> const &() const { return ptr; } }; int main() { shared_ptr<A> ptr; ptr = ConvertsToPtr(); // error here return 0; }
错误:
test.cpp: In function ‘int main()’: test.cpp:28:23: error: ambiguous overload for ‘operator=’ in ‘ptr = ConvertsToPtr()’ test.cpp:28:23: note: candidates are: test.cpp:9:8: note: shared_ptr<A>& shared_ptr<A>::operator=(const shared_ptr<A>&) test.cpp:9:8: note: shared_ptr<A>& shared_ptr<A>::operator=(shared_ptr<A>&&)
解决方法
g -g -antic -std = c 11 -o test main.cpp
VS2015设置全部默认.
问题是编译器尝试将ConvertsToPtr()返回的临时转换为shared_ptr对象.当编译器与explicit关键字一起使用时,这种转换永远不会使用构造函数.但是,在使用gdb进行检查时,似乎使用shared_ptr< A> const&()转换函数匹配适当的Type.这个转换然后返回一个const shared_ptr&在调用赋值运算符时,这一点不含歧义(这也与Frohmberg的结果相匹配).
但是,如果省略了显式,则返回一个shared_ptr的对象.这可以匹配赋值运算符的rvalue版本或者const lvalue版本.
根据N4296,表11,那么我们在构造转换构造函数之后,再有一个共享对象的值.然而,重载分辨率找到两个匹配,它们都在完全匹配之下(rvalue版本是Identity匹配,而另一个在Qualifying匹配下).
我也检查了VS2015,并在评论中说,它的作品.但是使用一些cout调试可以看出,const值赋值赋值rvalue优先于rvalue const lvalue refrence version对应.
编辑:我在标准上看了一点更深入,并添加了修改.关于结果VS2015的删除文本是错误的,因为我没有定义这两个作业.当两个作业都被宣布时,它更喜欢右值.
我认为VS编译器将标识从排名中的资格匹配中分离出来.但是,我总结说,这是VS编译器是错误的. g编译器遵守给定的标准.然而,由于GCC 5.0作为Visual studio工作,编译器bug的可能性很小,所以我很高兴看到另一个专家的见解.
编辑:在13.3.3.2其中一个抽奖者,在我写的更好的排名之后,是:
— 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.
附有一个示例,显示给定的rvalue(不是rvalue引用)应该匹配一个const int&&超过const int&因此,我猜想,我们可以放心地认为这与我们的案件有关,即使我们有&键入而不是const&&&类型.我猜,毕竟,GCC 4.7,4.8都是bug的.