【发布时间】:2012-09-08 19:09:33
【问题描述】:
考虑这个最小的例子:
#include <memory>
struct B {
typedef std::shared_ptr<B> Ptr;
};
struct A {
operator B::Ptr() { // type conversion operator <----+
return std::make_shared<B>(); // |
} // |
}; // |
// |
int main() { // |
A* a = new A; // |
B::Ptr{*a}; // copy construction from a's implicit cast to B::Ptr ----+
}
shared_ptr<B> 的这种无害复制构造 在 g++ 4.6.3 x86_64-linux-gnu 上严重失败,但似乎适用于 g++ 4.5(请注意,较新的版本中断,而较旧的作品!)。从错误中我可以看出(见下文)g++ 4.6 似乎通过值传递A,而不是通过(r 或 l)引用。
所以,问题是,哪个是正确的,哪个是错误的?这种行为应该失败吗?如果有,为什么?
据我了解转换规则,此时应该尝试隐式转换为B::Ptr ,对吧?
注意:我将此示例简化为纯粹的技术问题,并且此代码对于任何生产系统都没有意义。
这是准确的错误:
shp.cpp: In function ‘int main()’:
shp.cpp:17:12: error: no matching function for call to ‘std::shared_ptr<B>::shared_ptr(<brace-enclosed initializer list>)’
shp.cpp:17:12: note: candidates are:
/usr/include/c++/4.6/bits/shared_ptr.h:315:2: note: template<class _Alloc, class ... _Args> std::shared_ptr::shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...)
/usr/include/c++/4.6/bits/shared_ptr.h:266:17: note: constexpr std::shared_ptr<_Tp>::shared_ptr(std::nullptr_t) [with _Tp = B, std::nullptr_t = std::nullptr_t]
/usr/include/c++/4.6/bits/shared_ptr.h:266:17: note: no known conversion for argument 1 from ‘A’ to ‘std::nullptr_t’
/usr/include/c++/4.6/bits/shared_ptr.h:258:2: note: template<class _Tp1, class _Del> std::shared_ptr::shared_ptr(std::unique_ptr<_Up, _Ep>&&)
/usr/include/c++/4.6/bits/shared_ptr.h:253:2: note: template<class _Tp1> std::shared_ptr::shared_ptr(std::auto_ptr<_Tp1>&&)
/usr/include/c++/4.6/bits/shared_ptr.h:248:11: note: template<class _Tp1> std::shared_ptr::shared_ptr(const std::weak_ptr<_Tp1>&)
/usr/include/c++/4.6/bits/shared_ptr.h:236:2: note: template<class _Tp1, class> std::shared_ptr::shared_ptr(std::shared_ptr<_Tp1>&&)
/usr/include/c++/4.6/bits/shared_ptr.h:226:7: note: std::shared_ptr<_Tp>::shared_ptr(std::shared_ptr<_Tp>&&) [with _Tp = B, std::shared_ptr<_Tp> = std::shared_ptr<B>]
/usr/include/c++/4.6/bits/shared_ptr.h:226:7: note: no known conversion for argument 1 from ‘A’ to ‘std::shared_ptr<B>&&’
/usr/include/c++/4.6/bits/shared_ptr.h:218:2: note: template<class _Tp1, class> std::shared_ptr::shared_ptr(const std::shared_ptr<_Tp1>&)
/usr/include/c++/4.6/bits/shared_ptr.h:206:2: note: template<class _Tp1> std::shared_ptr::shared_ptr(const std::shared_ptr<_Tp1>&, _Tp*)
/usr/include/c++/4.6/bits/shared_ptr.h:184:2: note: template<class _Deleter, class _Alloc> std::shared_ptr::shared_ptr(std::nullptr_t, _Deleter, _Alloc)
/usr/include/c++/4.6/bits/shared_ptr.h:165:2: note: template<class _Tp1, class _Deleter, class _Alloc> std::shared_ptr::shared_ptr(_Tp1*, _Deleter, _Alloc)
/usr/include/c++/4.6/bits/shared_ptr.h:146:2: note: template<class _Deleter> std::shared_ptr::shared_ptr(std::nullptr_t, _Deleter)
/usr/include/c++/4.6/bits/shared_ptr.h:129:2: note: template<class _Tp1, class _Deleter> std::shared_ptr::shared_ptr(_Tp1*, _Deleter)
/usr/include/c++/4.6/bits/shared_ptr.h:112:11: note: template<class _Tp1> std::shared_ptr::shared_ptr(_Tp1*)
/usr/include/c++/4.6/bits/shared_ptr.h:103:7: note: std::shared_ptr<_Tp>::shared_ptr(const std::shared_ptr<_Tp>&) [with _Tp = B, std::shared_ptr<_Tp> = std::shared_ptr<B>]
/usr/include/c++/4.6/bits/shared_ptr.h:103:7: note: no known conversion for argument 1 from ‘A’ to ‘const std::shared_ptr<B>&’
/usr/include/c++/4.6/bits/shared_ptr.h:100:17: note: constexpr std::shared_ptr<_Tp>::shared_ptr() [with _Tp = B]
/usr/include/c++/4.6/bits/shared_ptr.h:100:17: note: candidate expects 0 arguments, 1 provided
【问题讨论】:
-
是什么让你认为这与
shared_ptr有任何关系?如果您只是创建某种类型并使用它来代替shared_ptr,会发生什么? -
它在 GCC 4.7.1 中工作(除了以反斜杠结尾的 cmets,导致多行注释问题)liveworkspace.org/code/d7713b217a30dc973795698adfd3c1c8,我相信它是正确的。 (但我必须说,我发现使用
operator B::Ptr创建 B 的新 shared-ptr 实例有点误导,因为该实例似乎不是 A 实例的任何类型的 转换形式。我相信这是因为我们正在处理一个简化的示例。) -
@NicolBolas:当然,我在发布之前就尝试过,但似乎效果很好。我怀疑它与 g++ 的
shared_ptr实现提供的构造函数重载有关。我不知道为什么旧版本有效。 -
@jogojapan:确实,正如我在 OP 中指出的那样,我试图删除所有对问题不重要的内容。
-
如果你提供一个自定义的简化智能指针类而不是 shared_ptr,这个问题会更清楚。在 MinGW 上使用 4.7.0 对我来说,您的代码似乎可以正常工作。没有看到 shared_ptr 的具体实现,很难明确地说“这是对的”或“这是错的”。关于这个问题,听起来 gcc 找不到 shared_ptr
& 的构造函数,我认为这是您的运算符的类型。有一个构造函数 const shared_ptr & tho...也许可以尝试定义 operator B::Ptr() const{...}?
标签: c++ c++11 compiler-errors g++ type-conversion