2016-05-15 22 views
8

Tôi quan tâm đến việc triển khai một môi trường giống như bộ sưu tập Java cho C++. Tôi biết đây không phải là một ý tưởng tốt và vân vân nhưng tôi không thực sự muốn sử dụng nó sau này, nhưng chỉ cần học cách thực hiện một số OOP nâng cao.Giao diện với chức năng thành viên mẫu

Vấn đề của tôi là tôi muốn mẫu lớp cơ sở collection<T> với các hàm thuần túy ảo. Một trong các chức năng này phải là map(), mất std::function<R(T)>. Vì map() phải là ảo Tôi không biết tôi nên sử dụng loại trả về nào. collection<R> là không thể vì các mẫu chức năng thành viên không thể là ảo.

Làm cách nào để thêm map() chức năng thành viên cho giao diện collection<T> của tôi?

+0

Có gì sai với các thùng chứa tiêu chuẩn C++? –

+2

@ πάντα ῥεῖ OP đang cố gắng làm điều này cho mục đích học tập tôi đoán. –

+0

không có gì tôi chỉ muốn biết làm thế nào để thực hiện một điều như vậy cho mục đích giáo dục – Exagon

Trả lời

7

Làm cách nào để thêm chức năng thành viên map cho giao diện collection<T> của tôi?

Câu trả lời ngắn gọn là: bạn không. Nếu tôi có một số collection<int> và tôi muốn mapstd::to_string vào nó, tôi cần phải tạo ra một collection<std::string>. Nhưng cần có vector_collection<int> để tạo ra một vector_collection<std::string>list_collection<int> cần phải tạo ra một list_collection<std::string> - do đó bản thân loại chuyển đổi đó cần phải là virtual bị đóng băng. Nhưng bạn không thể có virtual mẫu chức năng thành viên, vì vậy không có cách nào để diễn tả điều này.

Để làm việc này, bạn sẽ phải có một loại cơ sở chung cho tất cả các đối tượng bạn đang đặt trong vùng chứa của bạn và sau đó chỉ có một mặt tiền chung mà bạn có thể bỏ qua. Tức là, bạn thực sự chỉ có collection<unique_ptr<Object>> trong đó map chỉ cung cấp cho bạn collection<unique_ptr<Object>> khác và bạn chỉ cần mapcollection_facade<int, collection<unique_ptr<Object>>> của mình vào một collection_facade<std::string, collection<unique_ptr<Object>>>. Với rất nhiều công việc và hoàn toàn không quan tâm đến hiệu suất và loại an toàn, bạn có thể đến đó.


Đây là lợi thế của mẫu. Nếu tôi muốn viết map cho một cái gì đó giống như vector, tôi chỉ có thể viết rằng:

template <class T, class A, class F, class R = std::result_of_t<F(T)>> 
std::vector<R, A> map(std::vector<T, A> const& v, F f) { 
    std::vector<R, A> mapped; 
    mapped.reserve(v.size()); 
    for (T const& elem : v) { 
     mapped.push_back(f(elem)); 
    } 
    return mapped; 
} 

hay:

template <class T, class A, class F, class R = std::result_of_t<F(T)>> 
std::vector<R, A> map(std::vector<T, A> const& v, F f) { 
    return std::vector<R, A>(
     boost::make_transform_iterator(v.begin(), f), 
     boost::make_transform_iterator(v.end(), f) 
     ); 
} 

tôi phải thực hiện map() cho mỗi thùng chứa riêng - nhưng tôi sẽ phải làm điều đó dù sao. Và bây giờ tôi không đưa ra bất cứ điều gì. Bên cạnh đó, bạn có thường xuyên viết các thuật toán có thời gian chạy-container-bất khả tri không?

+0

Và 'cấp phát' cũng có thể được phục hồi. – Jarod42

0

Triển khai map làm hàm mẫu bên ngoài. Ví dụ: Ví dụ, bạn có thể phân tách map theo hai giai đoạn, nhà sản xuất ảo nội bộ và người tiêu dùng theo khuôn mẫu bên ngoài.

template<typename T> struct Collection { 
    // virtual T next(); // Java way 
    // C++ way 
    // In simplest cases you can rely on iterator pairs. 
    struct const_iterator { 
     T const &operator*() const; 
     const_iterator &operator++(); 
    } 
    virtual const_iterator begin() const; 
    virtual const_iterator end() const; 
}; 
template<typename R, typename T> Collection<R> map(
    Collection<T> const &coll, std::function<R(T)> const &f); 

Thực hiện container chất phức tạp và tác phẩm monadic bạn thậm chí có thể từ chối begin()end() và viết một rõ ràng (một phần) template đặc biệt.

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