2015-07-15 14 views
6

Tôi đang gặp phải một lỗi biên dịch cho đoạn mã sau:người dùng định nghĩa chức năng chuyển đổi và đúc để tham khảo

class SymbolGroup 
{ 
    std::string d_; 

public: 
    SymbolGroup(std::string a):d_(a){} 

    // explicit operator const std::string&() const { return d_;} // compiles 
    explicit operator std::string() const { return d_;} // Does not compile 
}; 

inline 
bool operator==(const SymbolGroup& lhs, const SymbolGroup& rhs) 
{ 
    return static_cast<const std::string&>(lhs) == 
    static_cast<const std::string&>(rhs); 
} 

int main(){ 

    SymbolGroup a("hello"); 
    SymbolGroup b("hello"); 

    if (a==b) 
    std::cout << "they are the same\n"; 

    return 0; 
} 

Nếu không có sự 'const' và '&' trong dòng chuyển đổi kiểu người dùng định nghĩa, nó không không biên dịch trong g ++ (4.8) với --std = C++ 11 cờ:

error: invalid initialization of reference of type ‘std::string& {aka std::basic_string&}’ from expression of type ‘const string {aka const std::basic_string}’ explicit operator std::string&() const { return d_;}

Mã biên dịch theo cả hai cách. Trình biên dịch nào là chính xác? Mã này có biên dịch với operator std::string() không?

+0

Tôi nhận được [không lỗi biên dịch] (http://cpp.sh/6wbj) – CoryKramer

+1

@CoryKramer Bạn đã biên dịch bằng phiên bản không có 'const' và '&'? – ENIGMA

+1

Chỉ cần thông tin - nếu bạn đang đặt câu hỏi về mã không biên dịch, tốt hơn bạn nên viết ví dụ dưới dạng mã không biên dịch sao cho mọi người có thể nhanh chóng sao chép và dán. – Barry

Trả lời

4

CẬP NHẬT câu trả lời trước của tôi là chính xác sai . Xin lỗi! tldr; clang là chính xác để chấp nhận mã, gcc là không chính xác để từ chối nó.


Thứ nhất, từ [expr.static.cast]:

An expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e) ; is well-formed, for some invented temporary variable t (8.5).

Vì vậy, hiệu quả, chúng tôi đang cố gắng để chỉ đạo-khởi tạo một đối tượng kiểu std::string const& một cách rõ ràng từ một đối tượng kiểu SymbolGroup const&. Có một phần đặc biệt trên khởi tạo các tham chiếu bởi một chức năng chuyển đổi: "Khởi tạo bởi chức năng chuyển đổi để tham khảo trực tiếp ràng buộc" [over.match.ref]:

Under the conditions specified in 8.5.3, a reference can be bound directly to a glvalue or class prvalue that is the result of applying a conversion function to an initializer expression. Overload resolution is used to select the conversion function to be invoked. Assuming that “cv1 T” is the underlying type of the reference being initialized, and “cv S” is the type of the initializer expression, with S a class type, the candidate functions are selected as follows:

— The conversion functions of S and its base classes are considered. Those non-explicit conversion functions that [...] are candidate functions. For direct-initialization, those explicit conversion functions that are not hidden within S and yield type “lvalue reference to cv2 T2” or “cv2 T2” or “rvalue reference to cv2 T2”, respectively, where T2 is the same type as T or can be converted to type T with a qualification conversion (4.4), are also candidate functions.

Phần đầu không áp dụng kể từ khi chuyển đổi chức năng của chúng tôi là explicit, vì vậy tôi đã bỏ qua nó. Phần thứ hai. Chúng tôi có cv1 T là const std::string, vì vậy chức năng chuyển đổi của chúng tôi là std::string là hàm ứng cử viên vì std::string có thể được chuyển đổi thành const std::string bằng chuyển đổi đủ điều kiện.


gcc là sai ở đây, và tôi nộp bug 66893, xác nhận bởi C++ chuyên gia rất riêng của chúng tôi và anh chàng xung quanh tốt Jonathan Wakely cũng như người đứng đầu Clang nhà phát triển và C++ biên tập chuẩn Richard Smith (sau khi tôi hoàn toàn xấu hổ bản thân mình nộp một lỗi Clang).

1

Vâng thưa bạn, câu trả lời tôi khá đơn giản. Thay vì đúc để tham chiếu const đổi lại như thế này:

return static_cast<const std::string&>(lhs) == static_cast<const std::string&>(rhs); 

Cast loại của bạn để std::string:

return static_cast<std::string>(lhs) == static_cast<std::string>(rhs); 

Và thưởng thức đang làm việc :)

+1

Điều này không trả lời được câu hỏi. Hơn nữa, OP muốn tránh sao chép chuỗi. – Barry

+1

Điều này là '(const std :: string &) (lhs) == (const std :: string &) (rhs);' biên dịch và 'static_cast (lhs) == static_cast (rhs); 'không. Sự khác biệt này có được nêu trong tiêu chuẩn không? – dewaffled

+0

AFAIK bằng cách sử dụng diễn viên kiểu c là nguy hiểm trong C++, bởi vì nó làm cho trình biên dịch chọn cách tự đúc.Vì vậy, nó có thể đồng thời thực hiện tĩnh, const nad diễn giải lại diễn viên. Có lẽ trong ví dụ của bạn nó sử dụng tĩnh và const đúc với nhau – bartop

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