在比较中使用用户定义的转换和隐式转换
using user-defined conversions with implicit conversions in comparisons
我正在努力理解为什么以下代码不允许发生隐式转换。
#include <string>
using namespace std;
struct HasConversionToString {
HasConversionToString(const string& s_) : s{s_} {}
string s;
operator const string&() const { return s; }
};
int main() {
string s{"a"};
HasConversionToString obj{"b"};
return s < obj;
}
clang 和 gcc 都未能找到一种有效的方法来比较两个对象,
错误如下:clang++ -std=c++14 -Wall -Wextra -pedantic conversion.cpp -o test
conversion.cpp:13:12: error: invalid operands to binary expression ('string' (aka 'basic_string<char>') and 'HasConversionToString')
return s < obj;
~ ^ ~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_pair.h:220:5: note: candidate template ignored: could not match
'pair' against 'basic_string'
operator<(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_iterator.h:298:5: note: candidate template ignored: could not match
'reverse_iterator' against 'basic_string'
operator<(const reverse_iterator<_Iterator>& __x,
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_iterator.h:348:5: note: candidate template ignored: could not match
'reverse_iterator' against 'basic_string'
operator<(const reverse_iterator<_IteratorL>& __x,
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_iterator.h:849:5: note: candidate template ignored: could not match
'__normal_iterator' against 'basic_string'
operator<(const __normal_iterator<_IteratorL, _Container>& __lhs,
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_iterator.h:856:5: note: candidate template ignored: could not match
'__normal_iterator' against 'basic_string'
operator<(const __normal_iterator<_Iterator, _Container>& __lhs,
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_iterator.h:1089:5: note: candidate template ignored: could not match
'move_iterator' against 'basic_string'
operator<(const move_iterator<_IteratorL>& __x,
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/stl_iterator.h:1095:5: note: candidate template ignored: could not match
'move_iterator' against 'basic_string'
operator<(const move_iterator<_Iterator>& __x,
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/basic_string.h:4989:5: note: candidate template ignored: could not match
'basic_string<type-parameter-0-0, type-parameter-0-1, type-parameter-0-2>' against 'HasConversionToString'
operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/basic_string.h:5001:5: note: candidate template ignored: could not match
'const _CharT *' against 'HasConversionToString'
operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.0/../../../../include/c++/5.3.0/bits/basic_string.h:5013:5: note: candidate template ignored: could not match
'const _CharT *' against 'string' (aka 'basic_string<char>')
operator<(const _CharT* __lhs,
^
1 error generated.
而当我将对象显式转换为字符串时,以下代码工作正常。
#include <string>
using namespace std;
struct HasConversionToString {
HasConversionToString(const string& s_) : s{s_} {}
string s;
operator const string&() const { return s; }
};
int main() {
string s{"a"};
HasConversionToString obj{"b"};
return s < static_cast<string>(obj);
}
根据 CPPPreferred 上列出的规则和示例,我认为这没有理由不起作用。我认为 clang 和 gcc 都没有搞砸同一件事,所以我想我有一个概念上的误解。
要调用的是一个函数模板:
template<class charT, class Traits, class Alloc>
bool operator<(std::basic_string<charT, Traits, Alloc> const& lhs,
std::basic_string<charT, Traits, Alloc> const& rhs);
第二个参数的演绎失败,因为HasConversionToString
不是std::basic_string
- 模板参数推导不会查看隐式转换。因此,将从重载解析中删除该函数模板。
std::experimental::basic_string_view
有一个类似的问题,这个问题通过"足够的附加重载"规则解决了(库必须添加足够的重载,以便basic_string_view
和可转换为一个的东西之间的比较有效)。
不过,你真的不希望basic_string
有这样的事情 - <
可能默默地导致堆的旅行并不是一个好主意。
http://en.cppreference.com/w/cpp/language/template_argument_deduction#Implicit_conversions
类型推导不考虑隐式转换(类型除外) 上面列出的调整):这是过载解决的工作, 这在以后发生。
相关文章:
- Visual C++(VS2017)中用户定义的转换不明确
- 变量定义到C++布尔值转换
- 有没有一种方法可以通过"typedef"为重新定义的基本类型定义特征和强制转换运算符
- 参数包构造函数在类模板中隐藏用户定义的转换
- C++:用户定义的显式类型转换函数错误
- 如何定义在用作函数参数时工作的类模板的转换
- 为什么转换函数声明不需要至少一个定义类型说明符
- 将文件复制到自定义位置,存在字符串转换问题
- 为什么从 char 转换为 std::byte 可能是未定义的行为?
- C++ 通过自定义赋值运算符隐式转换函数参数
- 虚拟成员函数的定义是否强制在同一转换单元中动态初始化静态数据成员?
- 用户定义的转换不能在C++中使用static_cast
- 用户定义的转换无法指定返回类型
- 如何在参数中定义隐式类型转换的构造函数?
- 是否可以创建一个用户定义的文本,将字符串文本转换为 own 类型的数组?
- 将结构 std::memcpy 转换为具有足够容量的 std::vector 是未定义的行为<char>吗?
- 在 C++ 中,我可以在不修改类的情况下定义对类的隐式转换吗?
- 过载分辨率和用户定义的转换
- 如何定义 typedefs 的隐式转换?
- 在unordered_map中,C2440"类型转换":无法转换...定义运算符 == 和hash_value时