c++ - 为 std::strings 重载 operator+ - 一个坏主意?
问题描述
现在通常应该稀疏地使用运算符重载 - 特别是当它涉及 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); ^
问题是operator+
找不到模板的定义。模板中的operator+
是通过不合格的名称查找来解决的。这基本上做了两件事:
在每个封闭范围内递归查找任何
operator+
内容,直到找到第一个。operator+
如果您为std::string
和在全局范围内或在不同的名称空间中定义自己的名称,那么当模板有任何“更接近”std::wstring
时,就无法以这种方式找到它。operator+
查看与运算符 (ADL) 的参数类型相关的命名空间。由于这两种类型都来自
namespace std
,我们在那里查看并发现没有任何operator+
工作(请参阅godbolt 上的其他错误说明)。您不能将自己的运算符放在那里,因为这是未定义的行为。
因此,经验法则:仅重载涉及您的类型的运算符,因为该运算符必须与您的类型放在相同的命名空间中才能使 ADL 工作。
即使没有模板,问题也是一样的,但在这种情况下,手动拉入操作员可能是合理的。要求通用代码(甚至可能不是你的)显然是不合理的。
推荐阅读
- java - Spring hibernate直到最后都没有提交
- wpf - 如何在 WPF 中重建逻辑树而不显示窗口
- python - 使用 Python 和 ftplib 在 FTP 服务器上发送图片的属性错误
- .net - Epplus 使用 TFS 连接创建 Excel
- python - 在 Redis 上存储和访问复杂 JSON 对象的最快和最佳方式
- javascript - jsReport不通过javascript读取数据
- ios - iOS AudioQueue 播放 AAC 数据总是延迟 2-3 秒
- perl - 使用 XML::LibXML 和 Perl 查找/替换值
- bash - 如何将命令的输出提供给提示符?
- android - 文本输入 EditText 数字不起作用?仅显示“abcxyz”之类的字符,并且还需要避免在edittext(TextInputLayout)中使用数字和符号