2008-11-05 41 views
14

Tôi có một số chức năng để tìm một giá trị:Làm thế nào tôi có thể phủ nhận một hàm trong C++ (STL)?

struct FindPredicate 
{ 

    FindPredicate(const SomeType& t) : _t(t) { 
    } 
    bool operator()(SomeType& t) { 
     return t == _t; 
    } 

private: 
    const SomeType& _t; 
}; 

bool ContainsValue(std::vector<SomeType>& v, SomeType& valueToFind) { 
    return find_if(v.begin(), v.end(), FindPredicate(valueToFind)) != v.end(); 
} 

Bây giờ tôi muốn viết một hàm để kiểm tra nếu tất cả các thành viên của một vector đáp ứng mà vị ngữ:

bool AllSatisfy(std::vector<SomeType>& v) { 
    /* ... */ 
} 

Một giải pháp là sử dụng thuật toán std::count_if.

Có ai biết giải pháp liên quan đến việc phủ nhận vị từ không?

Trả lời

20

Giải pháp tốt nhất là sử dụng STL functional library. Bằng cách phát hiện vị từ của bạn từ unary_function<SomeType, bool>, khi đó bạn sẽ có thể sử dụng hàm not1, thực hiện chính xác những gì bạn cần (tức là phủ nhận một biến vị ngữ đơn).

Đây là cách bạn có thể làm điều đó:

struct FindPredicate : public unary_function<SomeType, bool> 
{ 
    FindPredicate(const SomeType& t) : _t(t) {} 

    bool operator()(const SomeType& t) const { 
     return t == _t; 
    } 

private: 
    const SomeType& _t; 
}; 

bool AllSatisfy(std::vector<SomeType>& v, SomeType& valueToFind) 
{ 
    return find_if(v.begin(), 
        v.end(), 
        not1(FindPredicate(valueToFind))) == v.end(); 
} 

Nếu bạn muốn cuộn giải pháp của riêng bạn (đó là, IMHO, không phải là lựa chọn tốt nhất ...), tốt, bạn có thể viết một dự đoán đó là sự phủ định của người đầu tiên:

struct NotFindPredicate 
{ 

    NotFindPredicate(const SomeType& t) : _t(t) { 
    } 
    bool operator()(SomeType& t) { 
     return t != _t; 
    } 

private: 
    const SomeType& _t; 
}; 

bool AllSatisfy(std::vector<SomeType>& v) { 
    return find_if(v.begin(), 
        v.end(), 
        NotFindPredicate(valueToFind)) == v.end(); 
} 

Hoặc bạn có thể làm tốt hơn và viết một negator mẫu functor, như:

template <class Functor> 
struct Not 
{ 
    Not(Functor & f) : func(f) {} 

    template <typename ArgType> 
    bool operator()(ArgType & arg) { return ! func(arg); } 

    private: 
    Functor & func; 
}; 

mà bạn có thể sử dụng như sau:

bool AllSatisfy(std::vector<SomeType>& v, SomeType& valueToFind) 
{ 
    FindPredicate f(valueToFind); 
    return find_if(v.begin(), v.end(), Not<FindPredicate>(f)) == v.end(); 
} 

Tất nhiên, giải pháp thứ hai là tốt hơn bởi vì bạn có thể tái sử dụng struct Không với mỗi functor bạn muốn.

+0

Và sau đó bạn có thể thêm chức năng mẫu khuôn mẫu giống như người sgi đã trả lại đối tượng Không mà không cần phải chỉ định loại đó. – xtofl

7

Xem thư viện std functor not1, nó trả về một hàm functor không hợp lý cho bất kỳ hàm functor nào mà bạn cung cấp cho nó sẽ trả về.

Bạn sẽ có thể làm điều gì đó như:

bool AllSatisfy(std::vector<SomeType>& v, SomeType& valueToFind) { 
    return find_if(v.begin(), v.end(), not1(FindPredicate(valueToFind))) != v.end(); 
} 
2

Lần đầu tiên tôi sử dụng not1 Tôi tự hỏi tại sao nó không được gọi đơn giản là not.

Câu trả lời làm tôi ngạc nhiên một chút (xem nhận xét).

+0

Rõ ràng 'không' là biểu diễn thay thế được bảo lưu của ký hiệu '!' (Phần 2.11.2 trong tiêu chuẩn [lex.key]) – Motti

+2

Lý do khác là nó phân biệt sự phủ định của một vị từ đơn vị (not1) khỏi sự phủ định của một vị từ nhị phân (not2). –

0

Khi bạn đang sử dụng nó, bạn không cần hàm tìm kiếm của FindPredicate, vì trong ví dụ bạn chỉ kiểm tra sự bình đẳng.

bool all_equal(std::vector<SomeType>& v, SomeType& valueToFind) 
{ 
    return v.end() == find_if(v.begin(), v.end(), std::bind1st (equal_to(), valueToFind)); 
} 

bool all_not_equal(std::vector<SomeType>& v, SomeType &valueToFind) { 
{ 
    return v.end() == find_if(v.begin(), v.end(), std::bind1st (not_equal_to(), valueToFind)); 
} 

Và bạn chỉ có thể tự mình làm mẫu này.

template< typename InputIterator , typename Predicate > 
bool test_all(InputIterator first, InputIterator last, Predicate pred) 
{ 
    return last == find_if(first, last, pred); 
} 

test_all(v.begin(), v.end(), std::bind1st(not_equals_to_(value))); 
Các vấn đề liên quan