оператор перегрузки + для std :: strings - плохая идея? - PullRequest
2 голосов
/ 24 октября 2019

Теперь обычно перегрузку оператора следует использовать редко - в частности, когда это касается stdlib.

Хотя мне любопытно, какие могут быть подводные камни, если таковые имеются, кроме очевидных, что читатель может не ясно видеть, что происходитв коде - есть ли техническая причина воздерживаться от этой конкретной перегрузки?

std::string operator+(const std::string& lhs, const std::wstring& rhs) {
    return lhs + to_utf8(rhs);
}

(также существует двойная перегрузка для выполнения обратного преобразования)

Я считаю, что это может упростить запись некоторых операций, например ::

std::wstring{L"hel"} + "lo " + getName();

Какие плюсы и минусы, в частности, вы видите какие-либо сценарии (технические), где это может'backfire'?

Производительность не имеет значения.

Ответы [ 2 ]

5 голосов
/ 24 октября 2019

Вы не должны этого делать, потому что это нарушает Argument Dependent Lookup (ADL).

Рассмотрите этот невинный тестовый код:

namespace myNamespace
{
    struct MyType {};

    MyType operator+(MyType, MyType);

    template<class T>
    auto doSomething(T t)
    {
        return t + std::wstring{};
    }
}

Не выглядит проблематично, не так ли?

Ну, это:

void test()
{
    std::string s;
    myNamespace::doSomething(s);
}
error: invalid operands to binary expression ('std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >' and 'std::wstring' (aka 'basic_string<wchar_t>'))
        return t + std::wstring{};
               ~ ^ ~~~~~~~~~~~~~~

<source>:25:18: note: in instantiation of function template specialization 'myNamespace::doSomething<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >' requested here
    myNamespace::doSomething(s);
                 ^

<source>:12:12: note: candidate function not viable: no known conversion from 'std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >' to 'myNamespace::MyType' for 1st argument
    MyType operator+(MyType, MyType);
           ^

https://godbolt.org/z/bLBssp

Проблема в том, что ваше определение operator+ не найдено дляшаблон. operator+ в шаблоне разрешается с помощью поиска без определения имени. Это в основном делает две вещи:

  1. Ищите any operator+ рекурсивно в каждой охватывающей области, пока не найдет первую. Если вы определяете свои собственные operator+ для std::string и std::wstring в глобальной области или в другом пространстве имен, это не может быть найдено таким образом, когда любой operator+ "ближе" кtemplate.

  2. Просмотрите пространства имен, связанные с типами аргументов оператора (ADL). Поскольку оба типа относятся к namespace std, мы смотрим туда и не находим operator+, который работает (см. Другие примечания об ошибке на Годболте). Вы не можете поместить свой собственный оператор там, потому что это неопределенное поведение.

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


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

1 голос
/ 24 октября 2019

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

Легко просто написать to_utf8, когда вам это нужно.

Если у вас большое сочетание string и wstring, исправьте этов источнике: преобразуйте в UTF-8 в string, когда вы изначально получили ваши широкие строки, тогда все ваши строки «внутренне» хороши и последовательны.

...