2010-09-30 35 views
7

Trong mã này:Tại sao tôi cần chuyển đổi?

template<class T> 
struct Side 
{ 
}; 

template<class T> 
struct LeftSide : public Side<T> 
{ 
}; 
template<class T> 
struct RightSide : public Side<T> 
{ 
}; 

Side<int>* f(int left, int right) 
{ 
    return left < right ? new LeftSide<int> : new RightSide<int>;//<---Here I'm returning either left or right side 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    return 0; 
} 

tôi nhận được một lỗi:
_error 1 lỗi C2446: ':': không có chuyển đổi từ 'rightside *' thành 'leftside *' _

tôi đã nghĩ (sai như tôi thấy) mà tôi có thể gán con trỏ từ xuất phát đến cơ sở mà không có bất kỳ vấn đề. Vậy vấn đề nằm ở đâu?

Trả lời

14

Vấn đề không phải là với việc chuyển đổi từ một trong hai LeftSide hoặc RightSide để Side<T>. Như bạn nghĩ ban đầu, chuyển đổi này sẽ ổn.

Thay vào đó, vấn đề là với biểu thức này:

left < right ? new LeftSide<int> : new RightSide<int> 

Hãy phá vỡ này xuống một chút. Toán tử bậc ba (được gọi đúng trong Chuẩn như 'toán tử so sánh') trông giống như sau:

bool_val ? lhs_expression : rhs_expression 

Hãy nhớ rằng toàn bộ cấu trúc này chính là biểu thức. Có nghĩa là nó trả về một giá trị, mà phải có một loại, obv. Loại biểu thức toàn bộ được suy ra từ các loại lhs_expressionrhs_expression. Trong trường hợp này, bạn có LeftSideRightSide. Vì vậy, đây là vấn đề của bạn.

LeftSideRightSide không liên quan trực tiếp với nhau ngoài việc có lớp cơ sở chung và không có chuyển đổi nào giữa chúng. (Bạn sẽ phải viết một.) Vì vậy, không có datatype duy nhất mà bool_val ? lhs_expression : rhs_expression có thể có. Bạn có thể nghĩ, "tốt, trình biên dịch ngớ ngẩn, tại sao không chỉ tìm ra lớp cơ sở chung và sử dụng nó?" Đây thực sự là một nỗi đau. Để lại lập luận của nó là Đúng hay Sai sang một bên, nó không hoạt động theo cách đó.

Bạn có hai tùy chọn.

One, sử dụng một cấu trúc đơn giản hơn:

if(left < right) 
    return new LeftSide<int>; 
else 
    return new RightSide<int>; 

Hai, nếu bạn thực sự thực sự muốn sử dụng các nhà điều hành ternary (đó là trường hợp đôi khi), bạn cần phải muỗng thức ăn chăn nuôi trình biên dịch đó là kiểu dữ liệu:

Side<int>* f(int left, int right) 
{ 
    return left < right ? static_cast<Side<int>*>(new LeftSide<int>) : static_cast<Side<int>*>(new RightSide<int>);// now you're good 
} 
+1

(1) Bạn không thể viết chuyển đổi do người dùng xác định các kiểu con trỏ. (2) Bạn chỉ cần sửa kiểu của một toán hạng để nó hoạt động. (3) Thậm chí 'static_cast' là quá mức cần thiết vì một chuyển đổi ẩn tồn tại, và' static_cast' có thể ngăn cản trình biên dịch cảnh báo về các vấn đề an toàn kiểu hợp pháp. –

4

Tôi nghĩ rằng? : toán tử yêu cầu 2 lựa chọn là cùng loại; không phải là chúng có thể được chuyển đổi sang cùng loại

FYI gcc không giống nhau

error: conditional expression between distinct pointer types ‘LeftSide<int>*’ and ‘RightSide<int>*’ lacks a cast 

đúc cả Side (int) * công trình (nhưng có thể bạn biết rằng đã)

+2

Chuyển đổi là ok, nhưng một toán hạng phải chuyển đổi thành loại kia. Nếu bất kỳ loại nào được cho phép, vấn đề trở nên khó khăn trong trường hợp chung. –

+1

Tôi nghĩ rằng bạn đang đúng nhưng nó sooooo dissapointing! –

2

Bạn muốn cả các chi nhánh trả về Side<int>*, nhưng trình biên dịch không biết rằng, loại Side<int> không xuất hiện ở bất kỳ đâu trong biểu thức đó.

Vì tôi không muốn sử dụng một dàn diễn viên khi một chuyển đổi ngầm tồn tại, tôi muốn viết những dòng này như:

if (left < right) return new LeftSide<int>; 
return new RightSide<int>; 

Nhưng nếu bạn muốn sử dụng một nhà điều hành ternary,

Side<int>* i_want_this_type; 
return (left < right) ? new LeftSide<int> : (i_want_this_type = new RightSide<int>); 

Bây giờ nhánh bên phải là loại Side<int>*, tay trái có thể chuyển đổi thành kiểu đó, mọi thứ đều ổn (và trình biên dịch tối ưu hóa biến phụ).

+0

lý do cho downvote? –

+0

Tôi sẽ không có d/v'ed nhưng tôi đoán đó là bởi vì bạn đã giới thiệu một tạm thời - thậm chí tho tạm thời của nó trình biên dịch có thể tối ưu hóa trong hơi. –

0

Hai loại này phải là cùng loại hoặc một loại có thể chuyển đổi thành loại còn lại.

return left < right ? (Side<int>*)new LeftSide<int> : (Side<int>*)new RightSide<int>; 
+0

Dàn diễn viên kiểu C hoàn toàn quá mức ở đây. –

+0

Và xấu xí tàn bạo và cũ-out-of-date-lập trình-hasbeen-hack-ish –

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