Skip to main content
 首页 » 编程设计

c++之为 std::strings 重载运算符+之一个坏主意

2024年05月22日10youxin

现在通常应该稀疏地使用运算符重载 - 特别是当它涉及 stdlib 时。

虽然我很好奇可能存在哪些陷阱(如果有的话),但除了读者可能无法清楚地看到代码中发生的情况的明显陷阱之外,是否有任何技术理由避免这种>特定重载?

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

(还有用于进行反向变换的双重载)

我发现这可以使一些操作更容易写出来,例如:

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

优点和缺点是什么,特别是您是否看到任何可能“适得其反”的场景(技术场景)?

性能不是问题。

请您参考如下方法:

您不应该这样做,因为它会破坏参数依赖查找 (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. 在每个封闭范围中递归查找任何operator+,直到找到第一个。如果您在全局范围或不同的命名空间中为 std::stringstd::wstring 定义自己的 operator+,则不能当任何operator+“更接近”模板时发现这种方式。

  2. 查看与运算符 (ADL) 参数类型关联的命名空间。由于这两种类型都来自 namespace std,我们查看那里,发现没有可用的 operator+(请参阅 godbolt 上的其他错误注释)。您不能将自己的运算符放在那里,因为这是未定义的行为。

因此,经验法则:仅重载涉及您的类型的运算符,因为该运算符必须放置在与您的类型相同的命名空间中才能使 ADL 正常工作。

<小时 />

问题是 the same即使没有模板,但在这种情况下, pull in the operator manually 可能是合理的。要求通用代码(甚至可能不是您的)显然是不合理的。