5

tôi quyết định cố gắng để viết một thực hiện bản đồ chức năng trong C++ dùng mẫu có sẵn, và đây là những gì tôi đã đưa ra:chức năng C++ thông qua mẫu lạm dụng

template < 
    class U, 
    class V, 
    template <class> class T 
> 

class T<V> WugMap(
    class T<U>::const_iterator first, 
    class T<U>::const_iterator second, 
    V (U::*method)() const) 

{ 
    class T<V> collection; 
    while (first != second) 
    { 
     collection.insert(collection.end(), ((*(first++)).*method)()); 
    } 
    return collection; 
} 

Bây giờ đây là tất cả tiền phạt và dandy, và thậm chí biên dịch. Vấn đề là, tôi không có ý tưởng làm thế nào để thực sự gọi nó.

Cố gắng cách ngây thơ mang lại các lỗi sau:

prog.cpp:42: error: no matching function for call to 
‘WugMap(__gnu_cxx::__normal_iterator<Container*, std::vector<Container, 
std::allocator<Container> > >, __gnu_cxx::__normal_iterator<Container*, 
std::vector<Container, std::allocator<Container> > >, int (Container::*)()const)’ 

Theo như tôi có thể nói, tất cả các đối số là chính xác. gcc không gợi ý bất kỳ lựa chọn thay thế nào, điều này dẫn tôi đến việc tin rằng định nghĩa của tôi về WugMap là nghi ngờ, nhưng nó biên dịch tốt, vì vậy tôi khá lạc lõng. Bất cứ ai có thể hướng dẫn tôi thông qua silliness này?

Nếu bất cứ ai có thể đề xuất cách tốt hơn để viết một hàm như thế này sẽ hỗ trợ tiêu thụ bất kỳ loại bộ sưu tập nào chứa bất kỳ loại đối tượng nào, tôi sẽ xem xét thay đổi nó.

Here's my ideone so far.

Tôi hiện đang sử dụng Ideone, đó là sử dụng C++ 03, gcc 4.3.4.

Phụ lục 1

Đây có phải là có thể trong C++ 11? Nó đã được gợi ý rằng nó được. Tôi biết các mẫu trong C++ 11 hỗ trợ số lượng các đối số khác nhau vì vậy tôi sẽ sửa đổi các yêu cầu của tôi để phù hợp với điều đó là tốt. Tôi sẽ đặt một chút công sức vào viết cái gì đó lên, nhưng trong khi chờ đợi, đây là những yêu cầu mà tôi đang tìm:

  • nên có một cái gì đó chữ ký như sau:

    C2<V, ...> map(const C1<U, ...>&, V (U::*)(...), ...) 
    

    Đó là lấy một số bộ sưu tập C1, chứa các phần tử kiểu U, được xây dựng với một số tham số mặc định, tham chiếu, và cũng lấy một số hàm thành viên (trả về V và lấy một số đối số của các kiểu không xác định) của U và sau đó lấy , theo thứ tự, các đối số được chuyển đến hàm thành viên. Hàm cuối cùng sẽ trả về một tập hợp kiểu C2 chứa các phần tử kiểu V và được khởi tạo với một số lượng các tham số mặc định không xác định.

  • nên được thể kết nối:

    vector<int> herp = map(
            map(
             set<Class1, myComparator>(), 
            &Class1::getClass2, 2, 3), 
            &Class2::getFoo); 
    
  • thưởng điểm nếu tôi không cần phải có lập luận mẫu hay bất kỳ cách rườm rà phụ khác khi sử dụng nó.

std::transform thật tuyệt vời, nhưng không thể chuỗi.

+1

Có cần phải là vùng chứa không? ['std :: transform'] (http://www.cplusplus.com/reference/algorithm/transform/) trong' 'đã thực hiện điều này với các trình vòng lặp. –

+0

@JonPurdy: Hãy giả vờ rằng std :: transform không tồn tại. Ngoài ra, một tính năng mà việc triển khai này nhằm cung cấp std :: transform không phải là hàm con trỏ thành thành viên (tôi không nghĩ std :: transform có thể hoạt động theo cách này mà không có đối tượng bao bọc). Ngoài ra, std :: transform biến đổi một bộ sưu tập, nó được thiết kế để tạo ra một bộ sưu tập mới của một kiểu có thể khác. – Wug

+0

@DyP: bạn biết đấy, điều đó có thể liên quan đến nó, mặc dù chính xác là gì, tôi không thể hiểu được. Có một số loại quy tắc tinh tế về việc liệu có nên sử dụng 'class' hoặc' typename' không đi vào hoạt động trừ khi template-templates có liên quan hay không. Điều đó có thể giải thích lý do tại sao biên dịch của nó nhưng không được coi là một hàm mặc dù. – Wug

Trả lời

4

Đối số mẫu không bao giờ có thể được suy ra từ các loại lồng nhau. Ngay cả khi UV có thể được suy ra từ con trỏ hàm thành viên, bạn sẽ không thể suy ra loại mẫu T.

Chỉ định rõ ràng các đối số mẫu như trong liên kết đến ideone (Tôi không liên kết trước khi viết câu trên) cũng không hoạt động, chủ yếu là vì đối số mẫu cho std::vector không chỉ là một loại T!std::vector có loại giá trị và loại phân bổ. Sửa điều lên là nhận được khá xấu xí:

#include <vector> 
#include <iostream> 

using namespace std; 

class Container 
{ 
public: 
    Container() {} 
    Container(int _i) : i(_i) {} 

    int get_i() const {return i;} 

    int i; 
}; 

    template < 
     class U, 
     class V, 
     template <typename...> class T 
    > 

    T<V> WugMap(
     typename T<U>::const_iterator first, 
     typename T<U>::const_iterator second, 
     V (U::*method)() const) 
    { 
     T<V> collection; 
     while (first != second) 
     { 
      collection.insert(collection.end(), ((*(first++)).*method)()); 
     } 
     return collection; 
    } 

int main() 
{ 
    vector<Container> containers; 
    for (int i = 0; i < 10; ++i) containers.push_back((Container(i))); 

    WugMap<Container, int, std::vector>(
     containers.begin(), containers.end(), &Container::get_i); 
} 
+1

Anh ấy không suy luận, anh ta chỉ định rõ ràng: 'WugMap (...); ' –

+0

Điều này có nghĩa là tôi có thể chỉ định rõ ràng các đối số mẫu với' WugMap (...) ', nhưng điều đó cũng không hoạt động. – Wug

+0

Tôi đã thay đổi thành mã để xóa tham số và sử dụng biến thể variadics. –

2

Không thực sự chắc chắn cho dù đây phải là một câu trả lời, nhưng quái:

std::vector<std::string> src = f(); 
std::vector<std::string::size_type> sizes; 
sizes.reserve(src.size()); 
// Actual transformation: 
std::transform(src.begin(), src.end(), std::back_inserter(sizes), 
       [](std::string const& s) { return s.size(); }); 

điều tương tự có thể được thực hiện bằng tay, nhưng có thực sự là không có điểm trong reinventing bánh xe được tái tạo.

Như những gì là khác nhau trong trường hợp std::transform, nó không cố gắng để ràng buộc loại rất chặt chẽ, phải mất Iter1 cho hai đối số đầu tiên, cho số thứ ba và Functor cho ba. Không có séc trên giao diện để đảm bảo rằng Iter1 và là các trình vòng lặp vào cùng một loại vùng chứa hoặc Functor sẽ chuyển đổi từ loại giá trị trong vùng chứa đầu tiên sang loại giá trị trong giá trị thứ hai.

+0

Toàn bộ vấn đề không được sử dụng std :: transform bởi vì nó không hoạt động theo cách tôi muốn, và vì đó là một bài tập phát minh lại bánh xe là ok. – Wug

+0

Phần nào của 'std :: transform' không hoạt động như bạn muốn? Nó có thể đơn giản hơn để bắt đầu từ 'transform' và cải thiện nó để hỗ trợ nhu cầu của bạn hơn là bắt đầu từ đầu (đặc biệt là các yêu cầu nghiêm ngặt hơn về đối số' transform' là một lợi thế tốt không có trong cách tiếp cận của bạn -> cho ví dụ các thùng trộn cho đầu vào và đầu ra: tạo ra một 'tập' từ một' vector' –

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