2016-02-22 26 views
14

Tôi đang cố gắng hiểu tại sao mã sau không cho phép chuyển đổi tiềm ẩn xảy ra.sử dụng chuyển đổi do người dùng xác định với chuyển đổi tiềm ẩn so sánh

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

Cả kêu vang và gcc thất bại trong việc tìm ra một cách hợp lệ để so sánh hai đối tượng với các lỗi dọc theo dòng:

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. 

trong khi đoạn mã sau hoạt động tốt, khi tôi đúc một cách rõ ràng đối tượng để một chuỗi.

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

dựa trên các quy tắc và ví dụ được liệt kê on cppreference cho phôi tiềm ẩn, tôi thấy không có lý do nào không được. Tôi cho rằng cả clang và gcc đều không làm hỏng điều tương tự, vì vậy tôi tưởng tượng rằng tôi có một sự hiểu lầm về khái niệm.

Trả lời

16

Một bạn muốn gọi là một hàm 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); 

Trích thất bại cho đối số thứ hai vì một HasConversionToString không phải là một std::basic_string - mẫu luận khấu trừ không xem xét thông qua chuyển đổi tiềm ẩn. Kết quả là, mẫu chức năng đó được lấy ra khỏi độ phân giải quá tải.

std::experimental::basic_string_view có vấn đề tương tự, được giải quyết bằng quy tắc "quá tải bổ sung" (thư viện phải thêm quá tải để so sánh giữa basic_string_view và thứ gì đó có thể chuyển đổi thành một hoạt động).

Bạn không thực sự muốn một thứ như vậy đối với basic_string, mặc dù - có thể < có thể âm thầm gây ra một chuyến đi tới đống không thực sự là một ý tưởng hay.

+0

Đây có phải là trường hợp của SFINAE không? – MtRoad

+1

@MtRoad Không có sự thay thế nào ở đây. –

+0

Có cách nào phù hợp với điều này không? Tôi cố tình thực hiện chuyển đổi trả về một const & để tránh phân bổ không mong muốn không may. – David

Các vấn đề liên quan