Given this class:
class C
{
private:
struct Foo
{
int key1, key2, value;
};
std::vector<Foo> fooList;
};
The idea here is that fooList
can be indexed by either key1
or key2
of the Foo struct. I'm trying to write functors to pass to std::find_if
so I can look up items in fooList
by each key. But I can't get them to compile because Foo
is private within the class (it's not part of C's interface). Is there a way to do this without exposing Foo
to the rest of the world?
Here's开发者_高级运维 an example of code that won't compile because Foo
is private within my class:
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;
}
};
I'd do something like this.
Header:
class C
{
private:
struct Foo
{
int index;
Bar bar;
};
// Predicates used to find Notification instances.
struct EqualIndex;
struct EqualBar;
std::vector<Foo> fooList;
};
Source:
// 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;
};
Usage:
// 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.
}
Sort of...
Yes. Make the functor another member of C
and encapsulate std::find_if
behind a method of C
.
Following is an example:
#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;
}
You could make the functor a friend of C
.
The syntax is pretty baroque, but I could turn fooList
into a boost::multi_index_container
indexed on key1
and key2
.
If you don't need your struct inside your header you could also use unnamed namespaces in your implementation file to make the definitions and declarations local to the compilation unit (with static being the C-like alternative static
).
This leaves you with a cleaner header that isn't obscured by implementation details.
I could use the Pimpl Idiom to hide the private section of C
inside another class. Since everything in CImpl
can safely be public, I should be able to do whatever I want with Foo
there.
精彩评论