2016-02-22 6 views
14

Ich habe Schwierigkeiten zu verstehen, warum der folgende Code eine implizite Konvertierung nicht zulässig ist.Verwenden von benutzerdefinierten Konvertierungen mit impliziten Konvertierungen in Vergleichen

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

Beiden Klirren und gcc keine gültigen Weg finden, die beiden Objekte mit Fehlern entlang der Linien zu vergleichen:

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. 

während des folgenden Code funktioniert gut, wenn ich warf das Objekt explizit ein Faden.

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

auf der Grundlage der Regeln und on cppreference für implizite Abgüsse aufgeführten Beispiele, sehe ich keinen Grund, warum dies nicht funktionieren sollte. Ich nehme an, dass sowohl clang als auch gcc das gleiche nicht vermasselt haben, also stelle ich mir vor, dass ich ein konzeptionelles Missverständnis habe.

Antwort

16

Die Sie anrufen möchten, ist eine Funktionsvorlage:

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

Abzug für das zweite Argument fehl, weil ein HasConversionToString kein std::basic_string ist - Abzug Template-Argument nicht durch implizite Konvertierungen aussehen. Daher wird diese Funktionsvorlage aus der Überladungsauflösung entfernt.

std::experimental::basic_string_view hat ein ähnliches Problem, das durch eine "ausreichende zusätzliche Überladungen" Regel gelöst wurde (die Bibliothek muss genug Überlastungen hinzufügen, so dass der Vergleich zwischen einem basic_string_view und etwas zu einem konvertierbaren funktioniert).

Sie wollen nicht wirklich so eine Sache für basic_string, obwohl - < möglicherweise leise verursacht eine Reise auf den Haufen ist nicht wirklich eine gute Idee.

+0

Ist dies ein Fall von SFINAE? – MtRoad

+1

@MtRoad Hier gibt es keine Ersetzung. –

+0

Gibt es irgendeinen vernünftigen Weg? Ich machte absichtlich die Konvertierung zurück, um die unglückliche unerwartete Zuteilung zu vermeiden. – David