Не удалось найти оператор с помощью неявного преобразования в C ++

StackOverflow https://stackoverflow.com/questions/567626

Вопрос

При написании класса, который будет действовать как оболочка вокруг объекта, выделенного в куче, я столкнулся с проблемой неявного преобразования типов, которую можно свести к этому простому примеру.

В приведенном ниже коде класс-оболочка управляет объектом, выделенным в куче, и неявно преобразует в ссылку на этот объект.Это позволяет передавать объект-оболочку в качестве аргумента функции write(...), поскольку происходит неявное преобразование.

Однако компилятор терпит неудачу при попытке разрешить вызов operator<<(...), если не выполнено явное приведение (проверено с помощью компиляторов MSVC8.0, Intel 9.1 и gcc 4.2.1).

Итак, (1) почему в этом случае неявное преобразование завершается неудачей?(2) может ли это быть связано с поиском, зависящим от аргумента?и (3) есть ли что-нибудь, что можно сделать, чтобы заставить это работать без явного приведения?

#include <fstream>

template <typename T>
class wrapper
{
    T* t;
  public:
    explicit wrapper(T * const p) : t(p) { }
    ~wrapper() { delete t; }
    operator T & () const { return *t; }
};

void write(std::ostream& os)
{
    os << "(1) Hello, world!\n";
}

int main()
{
    wrapper<std::ostream> file(new std::ofstream("test.txt"));

    write(file);
    static_cast<std::ostream&>( file ) << "(2) Hello, world!\n";
    // file << "(3) This line doesn't compile!\n";
}
Это было полезно?

Решение

Это не удается, потому что вы пытаетесь разрешить оператор вашего wrapper<T> класс, которого не существует.Если вы хотите, чтобы это работало без актерского состава, вы могли бы собрать что-то вроде этого:

template<typename X> wrapper<T> &operator <<(X &param) const {
    return t << param;
}

К сожалению, я не знаю способа разрешить возвращаемый тип во время компиляции.К счастью, в большинстве случаев это тот же тип, что и объект, в том числе в данном случае с ostream.

Редактировать: Модифицированный код по предложению dash-tom-bang.Изменен тип возвращаемого значения на wrapper<T> &.

Другие советы

У компилятора недостаточно контекста, чтобы определить это operator& произведет действительное преобразование.Итак, да, я думаю, это связано с поиском, зависящим от аргумента:Компилятор ищет operator<< который может принять не-const wrapper<std::ostream> в качестве его первого параметра.

Я думаю, что проблема связана с поддержанием некоторых ограничений во время компиляции.В вашем примере компилятор сначала должен был бы найти ВСЕ возможный оператор<<.Затем для каждого из них следует попробовать, может ли ваш объект быть автоматически преобразован (прямо или косвенно) в любой из типов, которые каждый оператор<< способны принять.

Этот тест может быть действительно сложным, и я думаю, что он ограничен, чтобы обеспечить разумное время компиляции.

После некоторого тестирования еще более простой пример идентифицирует источник проблемы.Компилятор не может вывести аргумент шаблона T в f2(const bar<T>&) ниже из неявного преобразования wrapper<bar<int> > Для bar<int>&.

template <typename T>
class wrapper
{
    T* t;
  public:
    explicit wrapper(T * const p) : t(p) { }
    ~wrapper() { delete t; }
    operator T & () const { return *t; }
};

class foo { };

template <typename T> class bar { };

void f1(const foo& s) { }
template <typename T> void f2(const bar<T>& s) { }
void f3(const bar<int>& s) { }

int main()
{
    wrapper<foo> s1(new foo());
    f1(s1);

    wrapper<bar<int> > s2(new bar<int>());
    //f2(s2); // FAILS
    f2<int>(s2); // OK
    f3(s2);
}

В исходном примере, std::ostream на самом деле является typedef для шаблонного класса std::basic_ostream<..>, и та же ситуация применяется при вызове шаблонной функции operator<<.

Проверьте подпись оператора вставки...Я думаю, что они берут неконстантную ссылку ostream?

Подтверждено в стандарте C ++ 03 сигнатура оператора вывода char * равна:

template<class charT, class traits>
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);

который действительно использует неконстантную ссылку.Таким образом, ваш оператор преобразования не совпадает.

Как отмечено в комментарии:это не имеет значения.

В Стандарте существуют различные ограничения на применяемые преобразования...возможно, для этого потребовались бы неявные преобразования (ваш оператор и приведение к базовому типу), когда должно быть применено не более одного.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top