在比较中使用用户定义的转换和隐式转换 [英] using user-defined conversions with implicit conversions in comparisons

查看:216
本文介绍了在比较中使用用户定义的转换和隐式转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难理解为什么下面的代码不允许隐式转换发生。

  #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:二进制表达式的操作数无效('string'(aka'basic_string< char>')和'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:注意:候选模板被忽略:无法匹配
'pair'对'basic_string'
运算符<(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:注意:候选模板忽略:无法匹配
'reverse_iterator'对'basic_string'
运算符;(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:注意:候选模板忽略:无法匹配
'__normal_iterator'对'basic_string'
运算符<(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:注意:候选模板忽略:无法匹配
'move_iterator'对'basic_string'
运算符<(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:注意:候选模板忽略:无法匹配
'move_iterator'对'basic_string'
运算符<(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:注意:候选模板已忽略:无法匹配
'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:注意:候选模板忽略:无法匹配
'const _CharT *'对'HasConversionToString'
运算符<(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:注意:候选模板忽略:无法匹配
'const _CharT *'对'string'(aka'basic_string< char& b运算符<(const _CharT * __lhs,
^
1错误生成。

  #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);
}

在cppreference 隐式转换,我看到没有理由这不应该工作。我假设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 和可转换为一个工作之间的比较) p>

basic_string 虽然 - < 可能默默地导致访问堆是不是一个好主意。


I am struggling to understand why the following code does not allow an implicit conversion to occur.

#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;
}

Both clang and gcc fail to find a valid way to compare the two objects with errors along the lines of:

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.

whereas the following code works fine, when I explicitly cast the object to a string.

#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);
}

based on the rules and examples listed on cppreference for implicit casts, I see no reason this shouldn't work. I assume that both clang and gcc didn't screw up the same thing, so I imagine that I've got a conceptual misunderstanding.

解决方案

The one you want to call is a function template:

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);

Deduction fails for the second argument because a HasConversionToString is not a std::basic_string - template argument deduction doesn't look through implicit conversions. As a result, that function template is removed from overload resolution.

std::experimental::basic_string_view has a similar problem, which was solved by a "sufficient additional overloads" rule (the library must add enough overloads so that comparison between a basic_string_view and something convertible to one works).

You don't really want such a thing for basic_string, though - having < possibly silently causing a trip to the heap is not really a good idea.

这篇关于在比较中使用用户定义的转换和隐式转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆