2009-05-05 22 views
5

Tôi đã chơi về với functors trong C + +. Đặc biệt, tôi đã có một vectơ cặp tôi muốn sắp xếp theo yếu tố đầu tiên của cặp. Tôi bắt đầu viết một functor hoàn toàn chuyên biệt (tức là một cái gì đó như "bool MyLessThan (MyPair & lhs, MyPair & rhs)"). Sau đó, chỉ vì loại công cụ này là thú vị, tôi muốn thử viết một "Áp dụng F cho các yếu tố đầu tiên của cặp này" functor. Tôi đã viết dưới đây, nhưng g ++ không thích nó. Tôi nhận được:g ++ từ chối functor đơn giản của tôi với "mong đợi một loại, có 'xyz'"

lỗi: Loại/giá trị không phù hợp với lập luận 2 trong danh sách tham số mẫu cho 'mẫu struct Pair1stFunc2' lỗi: mong đợi một loại, có 'ít'

#include <algorithm> 
#include <functional> 
#include <utility> 
#include <vector> 

template <class P, class F> 
struct Pair1stFunc2 
{ 
    typename F::result_type operator()(P &lhs, P &rhs) const 
    { return F(lhs.first, rhs.first); } 

    typename F::result_type operator()(const P &lhs, const P &rhs) const 
    { return F(lhs.first, rhs.first); } 
}; 

typedef std::pair<int,int> MyPair; 
typedef std::vector<MyPair> MyPairList; 

MyPairList pairs; 

void foo(void) 
{ 
    std::sort(pairs.begin(), 
       pairs.end(), 
       Pair1stFunc2<MyPair, std::less>()); 
} 

bất cứ ai có thể rụng bất kỳ ánh sáng trên những gì tôi đang làm sai ở đây? Tôi biết đây là ví dụ nhân tạo một chút, nhưng tôi muốn biết chuyện gì đang diễn ra, nếu chỉ để cải thiện STL-fu của tôi.

+2

Khi bạn giải quyết vấn đề này, bạn sẽ có một thứ khác vì F là một loại. Bạn đang xây dựng một F mới bằng cách sử dụng lhs.first và rhs.first. Bạn sẽ thấy rằng std :: less không có một hàm tạo hai tham số. Bạn cần có một giá trị * * loại F. –

+0

Đây là một cái gì đó để cải thiện tăng của bạn :: bind-fu: sắp xếp (p.begin(), p.end(), bind (ít hơn (), bind (& MyPair: : đầu tiên, _1), liên kết (& MyPair :: đầu tiên, _2))); ;) http://codepad.org/NouR5fko –

Trả lời

2

Bạn cần chuyên std :: ít hơn với loại so sánh bạn đang sử dụng.

Pair1stFunc2<MyPair, std::less<int> >() 

sẽ thực hiện thủ thuật. Trong toán tử của riêng bạn() bạn cũng sẽ cần phải khởi tạo một đối tượng của kiểu so sánh, vì bạn không thể chỉ gọi trực tiếp lớp đó. Ví dụ. thay đổi

return F(lhs.first, rhs.first); 

để

F func; 
return func(lhs.first, rhs.first); 

Bạn cũng có thể di chuyển chuyên môn hóa vào functor, như câu trả lời khác gợi ý.

+0

Anh ấy không thực sự sử dụng std :: ít hơn với MyPair, tuy nhiên, nhưng std :: ít hơn thay thế. –

+0

Khá đúng, lỗi não trên một phần của tôi – Nik

3

Lưu ý rằng std::less chính nó là một mẫu và bạn không chỉ định thông số mẫu mẫu khi bạn gọi nó từ sốcủa hàm sort! Ở đây less là một loại không đầy đủ và do đó vấn đề.

6

Để mở rộng về câu trả lời của dirkgently, đây là một ví dụ về những gì có thể làm việc như bạn có ý định:

template <typename T, template <typename> class F> 
struct Pair1stFunc2 
{ 
    template <typename P> 
    typename F<T>::result_type operator()(P &lhs, P &rhs) const 
    { F<T> f; return f(lhs.first, rhs.first); } 

    template <typename P> 
    typename F<T>::result_type operator()(const P &lhs, const P &rhs) const 
    { F<T> f; return f(lhs.first, rhs.first); } 
}; 

void foo(void) 
{ 
    std::sort(pairs.begin(), 
       pairs.end(), 
       Pair1stFunc2<int, std::less>()); 
} 

Lưu ý rằng nó hoạt động, nhưng nó có thể không được chính xác những gì bạn có trong tâm trí.

+2

http://codepad.org/54PXQSoL –

+0

+1 cho mẫu không được chỉ định làm thông số mẫu. – mmmmmmmm

+0

Điều này làm việc, nhưng các tham số mẫu tiêu bản thực sự không cần thiết ở đây bởi vì bạn chỉ bao giờ tham chiếu đến F là "F " - xem câu trả lời của Martin York, cũng sẽ làm việc cho các trình so sánh không có khuôn mẫu. –

1

Giải pháp đơn giản nhất sẽ được nêu những gì bạn muốn là một cuộc tranh cãi, một chức năng với một chữ ký phù hợp:

template<typename P, bool (*F)(P,P)> struct Pair1stFunc2 { ... } 

Trong trường hợp này, đi qua một hàm template như là đối số thứ hai sẽ gây ra độ phân giải quá tải là thực hiện trên nó với P, P là loại đối số. Này hoạt động bởi vì bạn di chuyển độ phân giải quá tải ra khỏi struct Pair1stFunc2::operator()

Bạn cũng muốn khả năng đi qua trong một functor , nhưng những người cần phải được thông qua như là một đối số mẫu loại và sau đó tạo ra bên trong nhà điều hành():

typename F::result_type operator()(const P &lhs, const P &rhs) const 
{ return F()(lhs.first, rhs.first); } 

Ở đây, F là loại functor và F() một thể hiện của functor đó.

Trường hợp thứ ba đã được đề cập trước đó, mẫu functor. std :: less là một mẫu. Trong trường hợp đó, bạn cần một đối số mẫu khuôn mẫu.

+0

Về cơ bản chính xác, nhưng Tôi muốn nói rằng trường hợp của std :: ít là functors. Một hàm functor có thể được gọi bằng cách sử dụng cú pháp F (đối số-danh sách). Bạn không thể gọi std :: ít hơn như thế. – MSalters

+0

(đã xóa nhận xét của tôi vì nó được đề cập đến câu trả lời trước khi nó được chỉnh sửa) –

+0

Bạn đang đề xuất hai cú pháp riêng biệt cho Pair1stFunc2 :: operator() (lhs, rhs), một cho con trỏ hàm, cái khác cho functors? Được cấp, giải pháp của bạn sử dụng tham số mẫu con trỏ hàm sẽ nhỏ hơn và nhanh hơn cho trường hợp đó, nhưng bạn có thể sử dụng một cú pháp duy nhất bằng cách Pair1stFunc2 lấy hai tham số mẫu * type * (P và F) và lưu trữ thành viên f của loại F (điều này có thể được điền trong một ctor 1-arg cho trường hợp con trỏ hàm). Sau đó toán tử() (lhs, rhs) có thể nói "return f (lhs.first, rhs.first);". –

2

Tương tự như unwesen. Nhưng bạn không cần phải sử dụng mẫu template.

#include <algorithm> 
#include <functional> 
#include <memory> 
#include <vector> 

typedef std::pair<int,int> MyPair; 
typedef std::vector<MyPair> MyPairList; 
MyPairList pairs; 


// Same as original. 
template <typename T,typename F> 
struct Pair1stFunc2 
{ 
    template <typename P> 
    typename F::result_type operator()(P &lhs, P &rhs) const 
    { F f; // Just need to create an anstance of the functor to use. 
     return f(lhs.first, rhs.first); } 

    template <typename P> 
    typename F::result_type operator()(const P &lhs, const P &rhs) const 
    { F f; // Just need to create an anstance of the functor to use. 
     return f(lhs.first, rhs.first); } 
}; 


void foo(void) 
{ 
    std::sort(pairs.begin(), 
       pairs.end(), 
       Pair1stFunc2<int, std::less<int> >()); // initialize the version of less 
} 
+0

+1. Điều này là tổng quát hơn so với giải pháp của unwesel bởi vì nó cũng sẽ làm việc cho các bộ so sánh phi templated. –

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