Пользовательские операторы преобразования С++ без классов?

В С++ можно определить операторы преобразования, которые не являются членами класса? Я знаю, как это сделать для обычных операторов (таких как +), но не для операторов преобразования.

Вот мой вариант использования: я работаю с библиотекой C, которая выдает мне PA_Unichar *, где библиотека определяет PA_Unichar как 16-битное целое число. На самом деле это строка, закодированная в UTF-16. Я хочу преобразовать его в std::string, закодированный в UTF-8. У меня есть весь готовый и работающий код преобразования, и мне не хватает только синтаксического сахара, который позволил бы мне написать:

PA_Unichar *libOutput = theLibraryFunction();
std::string myString = libOutput;

(обычно в одной строке без переменной temp).

Также стоит отметить:

  • Я знаю, что std::string не определяет неявное преобразование из char*, и знаю почему. Здесь может быть та же причина, но это не относится к делу.

  • У меня есть ustring, подкласс std::string, который определяет правильный оператор преобразования из PA_Unichar*. Это работает, но это означает использование переменных ustring вместо std::string, а для этого then требуется преобразование в std::string, когда я использую эти строки с другими библиотеками. Так что это не очень помогает.

  • Использование оператора присваивания не работает, так как они должны быть членами класса.

Итак, возможно ли определить неявные операторы преобразования между двумя типами, которые вы не контролируете (в моем случае PA_Unichar* и std::string), которые могут быть или не быть типами класса?

Если нет, то какие могут быть обходные пути?


person Jean-Denis Muys    schedule 24.10.2009    source источник


Ответы (4)


Что не так с бесплатной функцией?

std::string convert(PA_Unichar *libOutput);

std::string myString = convert(theLibraryFunction());

Изменить ответ на комментарий:

Как говорит DrPizza: все остальные пытаются закрыть дыры, открытые неявными преобразованиями, заменяя их явными преобразованиями. который вы называете «визуальным беспорядком».

Что касается временной строки: просто дождитесь следующей версии компилятора. Вероятно, он будет поставляться со ссылками на rvalue, а его реализация std::string будет реализовывать семантику перемещения поверх этого, что устраняет копирование. Я еще не видел более дешевого способа ускорить ваш код, чем простое обновление до новой версии компилятора.

person sbi    schedule 24.10.2009
comment
что случилось? Немного, но все же две вещи: - визуальный беспорядок, когда у тебя сотни бессмысленных вызовов для конвертации - это решение подразумевает использование временного std::string. Это означает, что данные постоянно копируются дважды. Это может быть проблемой, а может и не быть, но не очень приятно. - person Jean-Denis Muys; 24.10.2009
comment
Большинство компиляторов оптимизируют лишнюю копию. - person rlbond; 24.10.2009
comment
jdmuys›rlbond прав, РВО распространен и реален на практике. Вы можете прочитать это: cpp-next. com/archive/2009/08/хочу-скорость-передавать-по-значению - person Klaim; 24.10.2009

В любом случае, неявные преобразования — это дьявол. Сделайте это явным с помощью вызова функции преобразования.

person DrPizza    schedule 24.10.2009
comment
Смотря как. Существуют реальные ситуации, когда неявные преобразования имеют смысл. Я обычно использую их, например, для преобразования одного типа в другой, который в семантических терминах является подмножеством другого. Например, если у вас есть класс person и класс employee, я ожидаю, что employee автоматически преобразуется в person везде, где ожидается последний. (Конечно, с другой стороны, неявное обратное преобразование было бы плохой идеей.) - person Mephane; 23.02.2011
comment
Я понимаю, что вы просто предложили гипотетический пример, но служащий как подкласс человека — плохой дизайн и моя любимая мозоль. Подклассы используются для отношения "является-отношением". Кажется, что сотрудник — это человек, но на самом деле это всего лишь часть двусмысленности английской грамматики. Сотрудник - это не особый тип человека, а роль, которую человек может иметь. На самом деле это отношения «иметь». - person ; 17.10.2012

Я не думаю, что вы можете определить «глобальные» операторы преобразования. Стандарты говорят, что conversion functions есть special member functions. Я бы предложил следующее, если бы мог рассмотреть следующий синтаксический сахар:

struct mystring : public string
{
    mystring(PA_Unichar * utf16_string)
    {
        // All string functionality is present in your mystring.
        // All what you have to do is to write the conversion process.
        string::operator=("Hello World!");
        string::push_back('!');
        // any string operation...
    }
};

Имейте в виду, что полиморфное поведение этого класса нарушено. Пока вы не создадите его объект с помощью указателя типа string*, вы в безопасности! Итак, этот код идеален:

mystring str(....);

Как было сказано ранее, следующий код не работает!

string* str = new mystring(....);
....
delete str; // only deleting "string", but not "mystring" part of the object
// std::string doesn't define virtual destructor
person AraK    schedule 24.10.2009

Нет, ты не можешь. В качестве альтернативы вы могли бы создать конструктор преобразования в целевом классе (не ваш случай, поскольку вы хотите преобразовать в std::string - если вы его не получите). Но я согласен с другими ответами, я думаю, что неявное преобразование в этом случае не рекомендуется, особенно потому, что вы конвертируете не из объекта, а из указателя. Лучше иметь бесплатную функцию, ваш код будет легче понять, и следующий программист, который унаследует код, обязательно поблагодарит вас.

person Fabio Ceconello    schedule 24.10.2009