Шаблоны C++ и проблема неоднозначности

У меня есть подмножество класса указателей, которые выглядят так:

template <typename T>
struct Pointer
{
     Pointer();
     Pointer(T *const x);
     Pointer(const Pointer &x);
     template <typename t>
     Pointer(const Pointer<t> &x);

     operator T *() const;
};

Цель последнего конструктора - позволить передать Pointer подкласса, или в основном любой тип, который неявно преобразуется в T *, Это фактическое правило обеспечивается только определением конструктора, и компилятор не может понять его только с помощью объявления. Если я уроню его и попробую пройти Pointer<Sub> конструктору Pointer<Base>, Я получаю ошибку компиляции, несмотря на возможный путь через operator T *(),

Хотя он решает вышеуказанную проблему, он создает еще одну. Если у меня есть перегруженная функция, чья одна перегрузка принимает Pointer<UnrelatedClass> а другой берет Pointer<BaseClass>и я пытаюсь вызвать его с Pointer<SubClass>Я получаю неоднозначность между двумя перегрузками с намерением, конечно, что последняя перегрузка будет вызвана.

Какие-либо предложения? (Надеюсь, я был достаточно ясен)

2 ответа

Решение

Лекарство от вашей проблемы называется SFINAE (ошибка замены не является ошибкой)

#include "boost/type_traits/is_convertible.hpp"
#include "boost/utility/enable_if.hpp"

template<typename T>
class Pointer {
   ...
   template<typename U>
   Pointer(const Pointer<U> &x,
      typename boost::enable_if<
         boost::is_convertible<U*,T*>
      >::type* =0)
   : ...
   {
     ...
   }
   ...
};

Если U* конвертируется в T*, enable_if будет иметь член typedef type по умолчанию аннулировать. То все в порядке. Если U* не конвертируется в T*, этот член typedef отсутствует, подстановка завершается неудачно, а шаблон конструктора игнорируется.

Это решает ваши проблемы конверсии и неоднозначности.

В ответ на комментарий: is_convertible выглядит примерно так:

typedef char one;         // sizeof == 1  per definition
struct two {char c[2];};  // sizeof != 1

template<typename T, typename U>
class is_convertible {
    static T source();
    static one sink(U);
    static two sink(...);
public:
    static const bool value = sizeof(sink(source()))==1;
};

Постарайтесь сделать этот конструктор явным, например:

 template <typename t>
 explicit Pointer(const Pointer<t> &x);

И / или удалить operator T *() const; - Я думаю, что это также создаст двусмысленность.

РЕДАКТИРОВАТЬ

Проверьте интерфейс std::auto_ptr и сравните с вашим. По крайней мере, они решили эту двусмысленность.

Другие вопросы по тегам