2015-02-06 17 views
5

Tôi tương đối mới để C++ và đây là bài viết đầu tiên của tôi, vì vậy hãy nhẹ nhàng ;-)Đi qua functor động STL

Tôi hiểu làm thế nào để vượt qua con trỏ hàm hay đối tượng chức năng, giống như nhiều chức năng stl yêu cầu. Không rõ với tôi cách sử dụng điều này kết hợp với thừa kế.

Cụ thể tôi muốn gọi hàm stl với một số hàm được kế thừa từ một hàm cơ sở. Tôi đã không tìm thấy bất kỳ nhận xét có liên quan hoặc thực tiễn tốt nhất về chủ đề này. Dưới đây là một đoạn mã đơn giản hóa mã:

struct generator{ 
    virtual int operator()() = 0; 
    virtual ~generator(){}; 
}; 

struct A : public generator{ 
    int operator()(); 
}; 

struct B : public generator{ 
    int operator()(); 
}; 

int main() 
{ 
    auto v = std::vector<std::array<int, 500>>(2); 
    std::array<std::shared_ptr<generator>, 2> functors = {{std::make_shared<A>(), 
                 std::make_shared<B>()}}; 
    for (size_t i = 0; i < functors.size(); ++i) 
    std::generate(std::begin(v[i]), std::end(v[i]), 
        *(functors[i])); 
    return 0; 
} 

Biên dịch này cung cấp cho:

clang++ -std=c++11 -g -Wall -Wextra test_stackoverflow.cpp 
test_stackoverflow.cpp:25:5: error: no matching function for call to 'generate' 
    std::generate(std::begin(v[i]), std::end(v[i]),*(functors[i])); 
    ^~~~~~~~~~~~~ 
/usr/lib/gcc/i686-linux-gnu/4.6/../../../../include/c++/4.6/bits/stl_algo.h:5003:5: note: candidate template ignored: substitution 
     failure [with _ForwardIterator = int *, _Generator = generator]: parameter type 'generator' is an abstract class 
    generate(_ForwardIterator __first, _ForwardIterator __last, 

Có loại * (functors [i]) là máy phát điện. Điều này sẽ không cho phép truy cập động vào toán tử A :: operator() và B ::(). Tôi hiểu làm thế nào để (giải quyết một cách thô lỗ) giải quyết vấn đề này. ví dụ.

std::generate(std::begin(v[i]), std::end(v[i], 
       [&]{ return functors[i]->operator()(); }; 

Tuy nhiên điều này có vẻ khá khó hiểu và tôi đang tìm cách rõ ràng hơn để đạt được mục tiêu của mình.

Làm thế nào để người ta thường vượt qua các functors năng động như vậy. Hoặc nếu điều này được cau mày, lựa chọn nào tốt nhất?

Bất kỳ trợ giúp hoặc đề xuất nào được hoan nghênh nhất.

Trả lời

1

Vấn đề, như bạn có thể đã biết, là std::generate sẽ mang máy phát điện theo giá trị. Để truyền một đối tượng đa hình, bạn phải vượt qua bằng tham chiếu.

Và có một giải pháp cho chính xác loại vấn đề này trong C++ 11 (bên cạnh tùy chọn lambda, vẫn còn thanh lịch hơn so với những gì chúng tôi đã có trước C++ 11, tôi tin). Giải pháp là std::ref. Nó trả về một trình bao bọc tham chiếu có thể được truyền theo giá trị.

này nên làm việc cho bạn:

std::generate(std::begin(v[i]), std::end(v[i]), 
       std::ref(*(functors[i]))); 

Lý do tại sao bạn có thể vượt qua wrappers tham chiếu như một functor, là họ thực hiện operator()

+0

Ngoài ra, 'std :: function' –

+0

xác nhận, có thể chuyển 'std :: ref' thành thuật toán. Không biết rằng. http://coliru.stacked-crooked.com/a/db815184c44240ad –

+0

Tôi sẽ thành thật. Tôi chưa bao giờ nghe nói về std :: ref. Vì vậy, cảm ơn bạn vì điều đó. Bạn có quan điểm rằng một lambda là để được ưa thích hơn này, và nếu như vậy tại sao? – APevar