Ошибка C ++ 0x: перегрузка функции с помощью std :: shared_ptr в аргумент const неоднозначна - PullRequest
6 голосов
/ 12 июня 2011

Предположим, у меня есть два несвязанных класса A и B.У меня также есть класс Bla, который использует boost::shared_ptr следующим образом:

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?Я использую стандартные версии GCC и Boost из репозитория пакетов Ubuntu 11.04, которые в настоящее время являются 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; -)

Ответы [ 4 ]

7 голосов
/ 12 июня 2011

shared_ptr имеет шаблонный конструктор с одним аргументом, который рассматривается для преобразования здесь.Это то, что позволяет указывать фактический параметр shared_ptr<Derived> там, где требуется shared_ptr<Base>.

Так как и shared_ptr<const A>, и shared_ptr<const B> имеют это неявное преобразование, это неоднозначно.

Впо крайней мере, в 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 ++.

Повышение не будет работать, поскольку отсутствует это требование.

Вот более простой тестовый пример: http://ideone.com/v4boA (Этот тестовый случай будетсбой на соответствующем компиляторе, если он успешно скомпилирован, это означает, что исходный регистр будет неверно указан как неоднозначный.)

VC ++ 2010 правильно (для std::shared_ptr).

6 голосов
/ 12 июня 2011

Следующее прекрасно компилируется с 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);
}
2 голосов
/ 13 июня 2011

Вы можете использовать std::static_pointer_cast, чтобы добавить const квалификацию:

bla.foo(std::static_pointer_cast<const A>(a));
0 голосов
/ 01 января 2012

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

В 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
{
}
...