Учитывая этот класс:
class C
{
private:
struct Foo
{
int key1, key2, value;
};
std::vector<Foo> fooList;
};
Идея здесь - это fooList
может быть индексирован также key1
или key2
из структуры Foo. Я пытаюсь записать функторы для передачи 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;
}
};
Я бы сделал что-то подобное.
Заголовок:
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.
}
Типа ...
Если вам не нужна структура внутри вашего заголовок, вы также можете использовать безымянные пространства имен в вашем файле реализации, чтобы сделать определения и объявления локальными для модуля компиляции (при этом static является альтернативой в стиле C static
).
Это оставляет вам более чистый заголовок, который не скрывается деталями реализации.
Да. Сделайте функтор другим членом C
и инкапсулируйте std :: find_if
в метод C
.
Ниже приводится пример:
#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;
}
Синтаксис довольно странный, но я мог бы превратить fooList
в boost :: multi_index_container
, индексированный на key1
и key2
.
Я мог бы использовать Pimpl Idiom, чтобы спрятать приватную секцию C
внутри другого класса. Поскольку все в CImpl
может быть публичным, я могу делать там с Foo
все, что захочу.