Puis-je écrire foncteurs en utilisant une struct imbriqué privée?
Question
Compte tenu de cette classe:
class C
{
private:
struct Foo
{
int key1, key2, value;
};
std::vector<Foo> fooList;
};
L'idée ici est que fooList
peut être indexé par l'une ou key1
key2
de la struct Foo. Je suis en train d'écrire foncteurs passer à std::find_if
je peux regarder par chaque touche articles dans fooList
. Mais je ne peux pas les amener à compilent parce Foo
est privé au sein de la classe (il ne fait pas partie de l'interface C). Est-il possible de le faire sans exposer Foo
au reste du monde?
Voici un exemple de code qui ne compile pas parce que Foo
est privé au sein de ma classe:
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;
}
};
La solution
Je ferais quelque chose comme ça.
En-tête:
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;
};
Utilisation:
// 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.
}
Trier des ...
Autres conseils
Oui. Faire foncteur un autre membre de C
et std::find_if
derrière une encapsulation méthode de C
.
Voici un exemple:
#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;
}
Vous pouvez faire foncteur un ami de C
.
La syntaxe est assez baroque, mais je pouvais fooList
en boost::multi_index_container
indexé sur key1
et key2
.
Si vous n'avez pas besoin de votre struct dans votre tête vous pouvez également utiliser les espaces de noms sans nom dans votre dossier de mise en œuvre pour que les définitions et les déclarations unité locale à la compilation (avec statique étant la static
autre type C).
Ceci vous laisse avec un en-tête de nettoyage qui n'est pas obscurci par des détails de mise en œuvre.
Je pourrais utiliser Pimpl Idiom pour cacher la partie privée de C
dans une autre classe. Puisque tout en CImpl
peut en toute sécurité publique, je serais capable de faire tout ce que je veux avec Foo
là.