Перегрузка глобального оператора преобразования типов - PullRequest
11 голосов
/ 10 февраля 2010

Для проверки и отображения результатов некоторых функций моей библиотеки я создаю набор удобных функций.

У меня есть функция execute, которая выглядит следующим образом:

template <typename R, typename I>
std::string execute( const std::string& func_name, R(*func_ptr)( const I& ), const I& func_input );

Вызывает функцию и отображает результаты и аргументы в отформатированной строке, которую я могу отправить std::cout.

Проблема в том, что некоторые из моих функций не возвращают преобразование в строку результатов. Я думал, что могу просто перегрузить глобальный ::operator std::string чем-то вроде:

template <typename T>
operator std::string( const std::vector<T>& v );

Но GCC жалуется:

error: 'operator std::string(const std::vector<T, std::allocator<_CharT> >&)' must be a nonstatic member function

Что ж, проблема, конечно, в том, что я не могу добавить операторы-члены к std::vector, и даже для своих классов я не хочу загрязнять их "для проверки" операторов преобразования.

Полагаю, я могу добавить слой косвенности и использовать функцию вместо оператора преобразования, но это не будет более эстетичным решением. Я также мог бы перегрузить ::operator << для std::ostream и использовать std::ostringstream, но это также не самое чистое решение.

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

Ответы [ 5 ]

12 голосов
/ 10 февраля 2010

Операторы преобразования (операторы приведения) должны быть членами конвертируемого класса, который создает преобразованный тип. Как операторы присваивания, они должны быть функциями-членами, как говорит вам ваш компилятор.

В зависимости от того, сколько усилий вы хотите приложить к его отладочной части, вы можете попытаться использовать метапрограммирование для перенаправления вашего метода execute в различные фактические реализации, предоставляя определенные для контейнеров, которые будут печатать содержимое.

Почему вы не хотите предоставить operator<< для ваших типов? Я думаю, что это на самом деле идиоматическое решение. В отличие от других языков, в которых вы используете методы, которые преобразуют в строку для получения результатов печати, в C ++ идиоматическим способом является operator<<, а затем использование stringstreams (или boost::lexical_cast или другое подобное решение) для преобразования в строки на основе operator<< реализация. Существует простой служебный класс здесь для создания string из элементов, которые переопределяют operator<<, если вы хотите использовать его для начальной точки.

5 голосов
/ 10 февраля 2010

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

Нет, такого нет. Функции преобразования должны быть членами класса. Если бы это было не так, это сделало бы разрешение перегрузки особенно неприятной проблемой для компилятора, введя неоднозначности.

1 голос
/ 10 февраля 2010

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

0 голосов
/ 31 марта 2013

К сожалению, не существует такого понятия, как глобальный оператор приведения. Удивительно. Но шаблоны - ваш друг.

Иногда вы не хотите показывать приведение к интерфейсу, который вы хотите оставить анонимным только для конкретной реализации. Я обычно добавляю в класс метод as (), который также может выполнять проверки типов в приведении и т. Д. И позволяет вам обрабатывать способ, которым вы хотите реализовать приведение (например, динамический, общий, ref и т.д.)

Примерно так:

    template< class EvtT >const EvtT& as() const throw( std::exception )
    {
        const EvtT* userData = static_cast<const EvtT*>( m_UserData );
        ASSERT( userData, "Fatal error! No platform specific user data in input event!" );
        return *userData;
    }

m_UserData - это анонимный тип, который известен только реализации. Хотя это строго типизированное приведение (я здесь не использую проверки типов), его можно заменить на dynamic_cast и правильные исключения приведения.

Реализация просто делает это:

    unsigned char GetRawKey( const InputEvent& ie )
    {
        const UserEvent& ue = ie.as<const UserEvent>();
        ...
0 голосов
/ 10 февраля 2010

Функция преобразования должна быть функцией-членом. Функция может не указывать тип возвращаемого значения, и список параметров должен быть пустым. Они должны использоваться экономно, и должен быть четкий путь преобразования из одного типа в другой. В противном случае они могут привести к неожиданным результатам и загадочным ошибкам.

...