2010-03-22 40 views
5

Với lớp này:Tôi có thể viết functors bằng cách sử dụng cấu trúc lồng nhau riêng không?

class C 
{ 
    private: 
     struct Foo 
     { 
      int key1, key2, value; 
     }; 
     std::vector<Foo> fooList; 
}; 

Ý tưởng ở đây là fooList có thể được lập chỉ mục bởi một trong hai key1 hay key2 của struct Foo. Tôi đang cố gắng viết các thư viện để chuyển đến std::find_if để tôi có thể tra cứu các mục theo số fooList theo từng khóa. Nhưng tôi không thể làm cho chúng biên dịch vì Foo là riêng tư trong lớp (nó không phải là một phần của giao diện của C). Có cách nào để thực hiện điều này mà không cần phơi bày Foo với phần còn lại của thế giới không?

Dưới đây là một ví dụ về mã đó sẽ không biên dịch vì Foo là tin trong lớp học của tôi:

struct MatchKey1 : public std::unary_function<Foo, bool> 
{ 
    int key; 
    MatchKey1(int k) : key(k) {} 
    bool operator()(const Foo& elem) const 
    { 
     return key == elem.key1; 
    } 
}; 

Trả lời

2

Tôi muốn làm điều gì đó như thế này.

Tiêu đề:

class C 
{ 
private: 
    struct Foo 
    { 
     int index; 
     Bar bar; 
    }; 

    // Predicates used to find Notification instances. 
    struct EqualIndex; 
    struct EqualBar; 

    std::vector<Foo> fooList; 
}; 

Nguồn:

// Predicate for finding a Foo instance by index. 
struct C::EqualIndex : std::unary_function<C::Foo, bool> 
{ 
    EqualIndex(int index) : index(index) { } 
    bool operator()(const C::Foo& foo) const { return foo.index == index; } 
    const int index; 
}; 

// Predicate for finding a Foo instance by Bar. 
struct C::EqualBar : std::unary_function<C::Foo, bool> 
{ 
    EqualBar(const Bar& bar) : bar(bar) { } 
    bool operator()(const C::Foo& foo) const { return foo.bar == bar; } 
    const Bar& bar; 
}; 

Cách sử dụng:

// Find the element containing the Bar instance someBar. 
std::vector<Foo>::iterator it = std::find_if(fooList.begin(), 
              fooList.end(), 
              EqualBar(someBar)); 

if (it != fooList.end()) 
{ 
    // Found it. 
} 

Sắp xếp của ...

+0

+1, tôi quên về việc đơn giản chuyển tiếp khai báo các functors thành các cấu trúc lồng nhau. Tôi đã sửa lỗi đánh máy (copy-and-paste-o?) Cho bạn. –

+0

@Kristo: copy-and-paste-o? bạn đặt cược-o! ;) –

1

Bạn có thể làm cho các functor một người bạn của C.

2

Có. Biến functor thành viên khác thành C và đóng gói std::find_if đằng sau phương thức C.

Sau đây là một ví dụ:

#include "stdafx.h" 
#include <vector> 
#include <cassert> 
#include <algorithm> 
#include <iostream> 

class C 
{ 
    private: 
     struct Foo 
     { 
      int key1, key2, value; 
     }; 

     std::vector<Foo> fooList; 

    struct Finder 
    { 
    private: 
     int key1, key2; 

    public: 
     Finder(int k1, int k2) 
     { 
     key1 = k1; 
     key2 = k2; 
     } 

     bool operator()(Foo const& foo) const 
     { 
     return foo.key1 == key1 || foo.key2 == key2; 
     } 
    }; 

public: 
    C() 
    { 
    Foo foo1, foo2; 
    foo1.key1 = 5; 
    foo1.key2 = 6; 
    foo1.value = 1; 
    foo2.key1 = 7; 
    foo2.key2 = 8; 
    foo2.value = 10; 

    fooList.insert(fooList.begin(), foo1); 
    fooList.insert(fooList.begin(), foo2); 
    } 

    int Find(int key1, int key2) 
    { 
    return std::find_if(fooList.begin(), fooList.end(), Finder(key1, key2))->value; 
    } 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    C c; 

    std::cout << c.Find(5, 3) << std::endl; 
    std::cout << c.Find(3, 6) << std::endl; 
    std::cout << c.Find(7, 3) << std::endl; 
    std::cout << c.Find(3, 8) << std::endl; 

    return 0; 
} 
1

Cú pháp là khá baroque, nhưng tôi có thể biến fooList trong đến một số boost::multi_index_container được lập chỉ mục trên key1key2.

+0

+1, cho tất cả các lần tôi đề nghị multi_index và không bao giờ được upvoted;) – pmr

0

Nếu bạn không cần cấu trúc bên trong tiêu đề, bạn cũng có thể sử dụng các không gian tên chưa được đặt tên trong tệp triển khai của bạn để tạo các định nghĩa và khai báo cục bộ cho đơn vị biên dịch (có dạng tĩnh là thay thế kiểu C static).

Điều này khiến bạn có tiêu đề sạch hơn không bị che khuất bởi chi tiết triển khai.

+0

Tôi nghĩ rằng 'Foo' vẫn cần phải được khai báo trong tiêu đề vì' fooList' phụ thuộc vào nó. –

+0

@Kristo: Chắc chắn, nhưng câu hỏi là về functor không phải là cấu trúc.Câu hỏi thực sự là nếu cấu trúc Foo thực sự chỉ là một chi tiết thực hiện hoặc nếu nó được cung cấp bên ngoài lớp học của bạn. – pmr

0

Tôi có thể sử dụng Pimpl Idiom để ẩn phần riêng tư của C bên trong một lớp khác. Vì mọi thứ trong CImpl có thể được công khai một cách an toàn, tôi có thể làm bất cứ điều gì tôi muốn với Foo tại đó.

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