2010-02-10 4 views
9

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

У меня есть 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.

Проблема в том, что некоторые из моих функций не возвращают convertible-to-string. Я думал, что я мог бы просто перегрузить глобальный ::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, но это также не самое чистое решение.

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

ответ

10

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

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

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

1

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

4

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

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

+1

Но многие операторы доступны как глобальный или член, почему это не один? Например, если существует глобальный и оператор-член <<, компилятор жалуется на двусмысленный вызов, он может сделать то же самое с конверсиями. – NewbiZ

+2

Функции преобразования - это специальные функции-члены (такие как ctor, dtor, op = и copy-constructor), поскольку они участвуют в создании конверсий/объектов. См. 12.3. – dirkgently

0

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

0

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

Иногда вы не хотите подвергать кастинг интерфейсу, который хотел бы оставить анонимным только для конкретной реализации. Обычно я добавляю метод template 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 является анонимным типом, который знает только реализация. Хотя это строго не типизированный листинг (я не использую здесь типа cecks), это может быть заменено на dynamic_cast и правильные исключения для литья.

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

unsigned char GetRawKey(const InputEvent& ie) 
    { 
     const UserEvent& ue = ie.as<const UserEvent>(); 
     ... 
Смежные вопросы