C++0x 错误:使用 std::shared_ptr 重载函数到 const 参数不明确

发布于 2024-11-14 20:28:53 字数 1484 浏览 3 评论 0 原文

假设我有两个不相关AB。我还有一个使用 boost::shared_ptrBla 类,如下所示:

class Bla {
public:
    void foo(boost::shared_ptr<const A>);
    void foo(boost::shared_ptr<const B>);
}

注意 const。这是这个问题的原始版本所缺少的重要部分。这可以编译,并且以下代码可以工作:

Bla bla;
boost::shared_ptr<A> a;
bla.foo(a);

但是,如果我在上面的示例中从使用 boost::shared_ptr 切换到使用 std::shared_ptr,则会出现编译错误那就是:

"error: call of overloaded 'foo(std::shared_ptr<A>)' is ambiguous
note: candidates are: void foo(std::shared_ptr<const A>)
                      void foo(std::shared_ptr<const B>)

你能帮我弄清楚为什么编译器无法弄清楚在 std::shared_ptr 情况下使用哪个函数,而在 boost::shared_ptr 情况下可以吗?我使用的是 Ubuntu 11.04 软件包存储库中的默认 GCC 和 Boost 版本,目前是 GCC 4.5.2 和 Boost 1.42.0。

以下是您可以尝试编译的完整代码:

#include <boost/shared_ptr.hpp>
using boost::shared_ptr;
// #include <memory>
// using std::shared_ptr;

class A {};
class B {};

class Bla {
public:
    void foo(shared_ptr<const A>) {}
    void foo(shared_ptr<const B>) {}
};

int main() {
    Bla bla;
    shared_ptr<A> a;

    bla.foo(a);

    return 0;
}

顺便说一句,这个问题促使我提出这个问题关于我是否应该使用std::shared_ptr;-)

Suppose I have two unrelated classes A and B. I also have a class Bla that uses boost::shared_ptr like this:

class Bla {
public:
    void foo(boost::shared_ptr<const A>);
    void foo(boost::shared_ptr<const B>);
}

Notice the const. That's the important part which the original version of this question lacked. This compiles, and the following code works:

Bla bla;
boost::shared_ptr<A> a;
bla.foo(a);

However, if I switch from using boost::shared_ptr to using std::shared_ptr in the above examples, I get a compilation error that says:

"error: call of overloaded 'foo(std::shared_ptr<A>)' is ambiguous
note: candidates are: void foo(std::shared_ptr<const A>)
                      void foo(std::shared_ptr<const B>)

Can you help me figure out why the compiler can't figure out which function to use in the std::shared_ptr case, and can in the boost::shared_ptr case? I'm using the default GCC and Boost versions from the Ubuntu 11.04 package repository which are currently GCC 4.5.2 and Boost 1.42.0.

Here is the full code that you can try compiling:

#include <boost/shared_ptr.hpp>
using boost::shared_ptr;
// #include <memory>
// using std::shared_ptr;

class A {};
class B {};

class Bla {
public:
    void foo(shared_ptr<const A>) {}
    void foo(shared_ptr<const B>) {}
};

int main() {
    Bla bla;
    shared_ptr<A> a;

    bla.foo(a);

    return 0;
}

By the way, this issue motivated me to ask this question about whether I should be using std::shared_ptr at all yet ;-)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

染墨丶若流云 2024-11-21 20:28:53

shared_ptr 有一个模板单参数构造函数,这里考虑将其用于转换。这就是允许在需要 shared_ptr 时提供实际参数 shared_ptr 的原因。

由于 shared_ptrshared_ptr 都有这种隐式转换,因此它是不明确的。

至少在 C++0x 中,标准要求 shared_ptr 使用一些 SFINAE 技巧来确保模板构造函数仅匹配实际可以转换的类型。

签名为(请参阅[util.smartptr.shared.const]部分):

shared_ptr<T>::shared_ptr(const shared_ptr<T>& r) noexcept;
template<class Y> shared_ptr<T>::shared_ptr(const shared_ptr<Y>& r) noexcept;

要求:第二个构造函数不得参与重载决策,除非 Y* 可以隐式转换为 T*

可能该库尚未更新以符合该要求。您可以尝试更新版本的 libc++。

Boost 不起作用,因为它缺少这个要求。

这是一个更简单的测试用例: http://ideone.com/v4boA (此测试用例在符合要求的编译器上将失败,如果编译成功,则意味着原始情况将被错误地报告为不明确。)

VC++ 2010 正确(对于 std::shared_ptr)。

shared_ptr has a template single-argument constructor, which is considered for the conversion here. That's what allows an actual parameter shared_ptr<Derived> to be supplied where a shared_ptr<Base> is needed.

Since both shared_ptr<const A> and shared_ptr<const B> have this implicit conversion, it's ambiguous.

At least in C++0x, the standard requires that shared_ptr use some SFINAE tricks to make sure that the template constructor only matches types that actually can be converted.

The signature is (see section [util.smartptr.shared.const]):

shared_ptr<T>::shared_ptr(const shared_ptr<T>& r) noexcept;
template<class Y> shared_ptr<T>::shared_ptr(const shared_ptr<Y>& r) noexcept;

Requires: The second constructor shall not participate in the overload resolution unless Y* is implicitly convertible to T*.

Possibly the library hasn't yet been updated to comply with that requirement. You might try a newer version of libc++.

Boost won't work, because it's missing that requirement.

Here's a simpler test case: http://ideone.com/v4boA (This test case will fail on a conforming compiler, if it compiles successfully, it means the original case will be incorrectly reported as ambiguous.)

VC++ 2010 gets it right (for std::shared_ptr).

树深时见影 2024-11-21 20:28:53

以下代码可以在 GCC 4.5 和 Visual Studio 10 中正常编译。如果您说它无法在 GCC 4.5.2 中编译,那么它听起来像是您应该报告的编译器错误(但请确保它确实发生,更有可能是您创建的)某种打字错误)。

#include <memory>
class A{};
class B{};
class Bla {
public:
    void foo(std::shared_ptr<A>) {}
    void foo(std::shared_ptr<B>) {}
};

int main()
{
    Bla bla;
    std::shared_ptr<A> a;
    bla.foo(a);
}

The following compiles fine with GCC 4.5 and Visual Studio 10. If you say it doesn't compile in GCC 4.5.2 then it sounds like a compiler bug which you should report (but make sure that it really happens it's more likely that you made some sort of typo).

#include <memory>
class A{};
class B{};
class Bla {
public:
    void foo(std::shared_ptr<A>) {}
    void foo(std::shared_ptr<B>) {}
};

int main()
{
    Bla bla;
    std::shared_ptr<A> a;
    bla.foo(a);
}
篱下浅笙歌 2024-11-21 20:28:53

您可以使用 std::static_pointer_cast 添加 const 限定:

bla.foo(std::static_pointer_cast<const A>(a));

You can use std::static_pointer_cast to add the const qualification:

bla.foo(std::static_pointer_cast<const A>(a));
七颜 2024-11-21 20:28:53

http://bytes.com/topic/c /answers/832994-shared_ptr-driven-classes-ambiguity-overloaded-functions

struct yes_type { char dummy; };
struct no_type { yes_type a; yes_type b; };

template < typename From, typename To >
class is_convertible
{
    private:
        static From* dummy ( void );

        static yes_type check ( To );

        static no_type check ( ... );

    public:

        static bool const value = sizeof( check( *dummy() ) ) == sizeof( yes_type );

}; // is_convertible

在boost的shared_ptr.h中,更改构造函数签名至:

template<class Y>
shared_ptr(shared_ptr<Y> const & r,
    typename enable_if<is_convertible<Y*, T*>::value, void*>::type = 0
    ): px(r.px), pn(r.pn) // never throws
{
}

http://bytes.com/topic/c/answers/832994-shared_ptr-derived-classes-ambiguitity-overloaded-functions

struct yes_type { char dummy; };
struct no_type { yes_type a; yes_type b; };

template < typename From, typename To >
class is_convertible
{
    private:
        static From* dummy ( void );

        static yes_type check ( To );

        static no_type check ( ... );

    public:

        static bool const value = sizeof( check( *dummy() ) ) == sizeof( yes_type );

}; // is_convertible

An in boost's shared_ptr.h, change the constructor signature to:

template<class Y>
shared_ptr(shared_ptr<Y> const & r,
    typename enable_if<is_convertible<Y*, T*>::value, void*>::type = 0
    ): px(r.px), pn(r.pn) // never throws
{
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文