2010-03-22 60 views
5

鑑於這種類:我可以使用私有嵌套結構來編寫函子嗎?

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

的這裏的想法是,fooList可以通過key1或富結構的key2索引。我正在嘗試編寫函子來傳遞給std::find_if,這樣我就可以通過每個鍵在fooList中查找項目。但是我不能讓它們編譯,因爲Foo在類中是私有的(它不是C的接口的一部分)。 有沒有辦法做到這一點,而不會將Foo暴露給世界其他地方?

這裏是代碼的例子,將不能編譯,因爲Foo是我的類中私有:

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; 
    } 
}; 

回答

2

我會做這樣的事情。

頁眉:

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

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

    std::vector<Foo> fooList; 
}; 

來源:

// 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; 
}; 

用法:

// 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. 
} 

排序... ...

+0

+1,我忘記了簡單地向前聲明仿函數是嵌套結構。我也修復了一個錯字(複製和粘貼o?)。 – 2010-03-22 17:00:28

+0

@Kristo:複製並粘貼o?你打賭 - 哦! ;) – 2010-03-22 20:43:08

1

你可以做的仿函數的C的朋友。

2

是。使仿函數的C另一名成員和封裝std::find_ifC方法落後。

下面是一個例子:

#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

的語法是相當巴洛克式,但我可以把fooList in到在key1key2索引的boost::multi_index_container

+0

+1,因爲我一直建議multi_index,從來沒有得到過投票;) – pmr 2010-03-22 16:01:22

0

如果你的頭文件中不需要你的結構,你也可以在你的實現文件中使用未命名的命名空間來使定義和聲明成爲編譯單元本地的定義和聲明(靜態是類似C的替代static)。

這讓你不由實現細節掩蓋一個更清潔的頭。

+0

我覺得'Foo'仍然需要在頭文件中聲明,因爲'fooList'依賴於它。 – 2010-03-22 16:24:52

+0

@Kristo:當然,但問題是關於函數而不是結構本身。真正的問題是,如果結構Foo真的只是一個實現細節,或者它應該在你的類之外提供。 – pmr 2010-03-22 20:45:18

0

我可以使用Pimpl Idiom隱藏的C另一個類中的私有部分。由於CImpl中的所有內容都可以安全地公開,因此我應該可以通過Foo來執行我想要的任何操作。

相關問題