2012-06-21 27 views
6

Tôi có một mã Java, trong đó kiểu trả về của một hàm có kiểu ký tự đại diện không bị chặn (?). Làm thế nào tôi có thể mô phỏng một cái gì đó như thế này trong C + +? ví dụ.Làm thế nào để mô phỏng 'dấu hỏi (?)' Loại generics trong Java tới C++?

public GroupHandlerSetting<?> handleGroupProcessingFor(final EventHandler<T> eventHandler) 
    { 
     return new GroupHandlerSetting<T>(eventHandler, eventProcessors); 
    } 
+4

Và các mẫu C++ thậm chí không giống như Java Generics. Các mẫu C++ tạo các kiểu mới; Java Generics hạn chế các kiểu hiện có. Các mẫu C++ về cơ bản là tiền xử lý với một số quy tắc kiểu ghép trên; Java Generics được xây dựng trên lý thuyết loại. Đừng bị quyến rũ bởi các ký hiệu nghĩ rằng chúng gần tương đương. Họ thì không. – EJP

+3

Joshua Bloch tuyên bố trong các video khác nhau mà không nên sử dụng các ký tự đại diện cho các loại trả lại. Bạn có chắc chắn rằng họ là một ý tưởng tốt trong trường hợp của bạn? Bạn có thể đăng chức năng hoặc ít nhất chữ ký của nó không? – fredoverflow

+0

xin vui lòng, bạn có thể thêm chức năng? –

Trả lời

6

Trong C++ tất cả đối số kiểu phải có tên, cho dù bạn sử dụng hay không, vì vậy không có dấu chấm hỏi. Chỉ cần làm cho nó một đối số mẫu cho hàm và đặt tên cho nó và bạn sẽ ổn.

template <typename T> 
struct templ { 
    template <typename U> 
    void assign(templ<U> & u);  // public void assign<?>(temple<U> u)  
}; 

Đó là một phần nhỏ, phần phức tạp hơn là thực thi những hạn chế về các loại, và cho rằng bạn có thể sử dụng SFINAE:

template <typename T> 
struct templ { 
    template <typename U, typename _ = std::enable_if< 
           typename std::is_base_of<U,T>::value 
             >::type > 
    void super(templ<U> & u);  // public void super_<? super T>(templ<?> u) 

    template <typename U, typename _ = std::enable_if< 
           typename std::is_base_of<T,U>::value 
             >::type > 
    void extends(templ<U> & u);  // public void extends_<? extends T>(templ<?> u) 
} 

Đó là sử dụng C++ 11 cho SFINAE, trong C++ 03, nó phức tạp hơn một chút (như thể phiên bản này là đơn giản) vì bạn không thể sử dụng SFINAE trên một đối số mẫu hàm, vì vậy SFINAE cần được áp dụng cho kiểu trả về hoặc đối số hàm bổ sung. SFINAE là một giải pháp mạnh mẽ hơn nhiều, nó có thể được sử dụng không chỉ để cung cấp superextends mà còn với nhiều tính năng khác của loại hoặc giá trị thời gian biên dịch. Google cho SFINAE và bạn sẽ tìm thấy nhiều trường hợp SFINAE được sử dụng, nhiều trường hợp sẽ là kiểu C++ 03.

Đã có đề xuất cho các khái niệm sẽ đơn giản hóa cú pháp, nhưng không đạt được thỏa thuận và trong một động thái để đẩy tiêu chuẩn hoàn thành, nó được hoãn lại cho tiêu chuẩn sau. Bây giờ, điều này thực sự không phổ biến trong C++ vì nó là trong Java, vì vậy tôi khuyên bạn nên cung cấp một câu hỏi khác với những gì bạn muốn làm, và bạn sẽ có ý tưởng cho các mẫu thiết kế trong C++ thành ngữ hơn.

+2

Đây không phải là điều tương tự. So sánh hai trang này tại trang web cuộc gọi: http://ideone.com/2LXUp và http://ideone.com/bMMJr. Nếu bạn muốn mô phỏng ký tự đại diện, bạn cần loại xóa. –

+0

@ R.MartinhoFernandes: Mẫu và Generics không giống nhau, nhưng bạn có thể thực hiện tất cả các mã chung chung có thể được thực hiện với Generics bằng cách sử dụng mẫu. Như ví dụ của bạn, C++ không hỗ trợ mã * * đặc biệt, lưu ý rằng các chuyên gia trong Java khuyên bạn không nên sử dụng '?' Trong câu lệnh trả về, lý do là việc thực hiện phương thức * biết * kiểu, vì vậy không có lý do không xuất bản nó. Ưu điểm duy nhất mà '?' Cung cấp trong kiểu trả về là bạn không cần phải biên dịch lại người gọi nếu callee trả về một kiểu khác cho trình giữ chỗ ... –

+0

... nhưng điều đó có hiệu quả vô dụng trong C++, dưới dạng mẫu * phải được biên dịch lại *, do đó, khả năng tương thích nhị phân (và có thể sử dụng một loại tê liệt tại trang web cuộc gọi - một loại mà bạn biết một vài tính năng nhỏ nhưng hiệu quả không rõ với bạn) không phải là một tính năng. Trong ví dụ của bạn, trong phiên bản Java, bạn luôn luôn trả về một 'ArrayList ', vì vậy ví dụ tương đương trong C++ sẽ là một hàm không chung chung: 'std :: vector getSomeList()'. Trong câu hỏi, phương thức này là một phần của một lớp chung (đoán từ 'T'), do đó một hàm thành viên không có khuôn mẫu của một khuôn mẫu. –

1

Ví dụ cụ thể của bạn được thực hiện dễ dàng và vì tôi không sử dụng Java, tôi không thể hiểu tại sao cần có <?> ở đó. Trong C++, bạn chỉ cần điền vào các thông số mẫu giống nhau:

template<class T> 
GroupHandlerSetting<T> handleGroupProcessingFor(EventHandler<T> const& evHandler){ 
    return GroupHandlerSetting<T>(evHandler, evProcessors); 
} 

T sẽ được rút ra từ bất kỳ đối số được truyền đến handleGroupProcessingFor, và chúng tôi chỉ sử dụng cùng một T cho kiểu trả về, về cơ bản chính xác những gì bạn làm trong các phần thân của hàm.

+0

Tôi không chắc chắn về điều này. Nếu tôi chỉ có thể thay thế bằng thì tôi nghĩ rằng cũng có thể thực hiện trong Java. Không chắc chắn lý do tại sao là cần thiết. Tôi có ít kiến ​​thức về Java nên tôi có thể sai. – polapts

+1

@polapts: Đọc nhận xét về câu trả lời của David, có vẻ như '' là cần thiết cho xóa bỏ kiểu. Trong ví dụ cụ thể của bạn, bạn có thể lấy đi bằng cách khấu trừ đối số đơn giản. – Xeo

+0

@Xeo: '?' Là một trình giữ chỗ kiểu, về cơ bản một đối số kiểu khác mà bạn thậm chí không quan tâm đến tên. Bạn có thể đặt một số ràng buộc về loại * unknown * là gì, cụ thể là bạn có thể yêu cầu nó là một cơ sở hoặc lấy được từ một kiểu khác (cho dù đối số chung hay kiểu cố định). Sự khác biệt giữa mã của bạn và mã câu hỏi là trong mã của bạn, kiểu 'T' bị ràng buộc giống nhau trong cả đối số và câu lệnh trả về, trong khi trong mã của câu hỏi thì không phải (nội bộ bạn có thể trả về' GroupHandlerSetting 'bất kể' T' và nó sẽ biên dịch là gì. –

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