Um mein Verständnis von C++ 11 zu erweitern, experimentiere ich damit, funktionale Helfer zu schreiben und zu sehen, ob ich sie weniger ausführlich nennen kann. Im Moment versuche ich eine some
Funktion zu schreiben, die wahr zurückgibt, wenn irgendein Gegenstand in einer Sammlung einen Test besteht. Ich möchte, dass es mit jedem Sammlungs-Typ funktioniert, in der Lage ist, aufrufbar zu sein und keine Template-Argumente zu benötigen.C++: Wie kann ich eine Funktion überladen, so dass es jeden Funktor einschließlich Zeiger auf Elementfunktionen nehmen kann?
Im Grunde möchte ich es so, dass der folgende Code arbeiten kompilieren:
// insert declaration of some here
#include <list>
#include <functional>
class Foo {
public:
bool check() const { return true; };
};
class DerivedFooList : public std::list<Foo> {
public:
DerivedFooList(std::initializer_list<Foo> args) : std::list<Foo>(args) {};
};
class DerivedFooPtrList : public std::list<Foo *> {
public:
DerivedFooPtrList(std::initializer_list<Foo *> args) : std::list<Foo *>(args) {};
};
bool intCheck(int a) { return a == 1; }
bool fooCheck(const Foo &a) { return a.check(); }
bool fooPtrCheck(const Foo *a) { return a->check(); }
int main()
{
Foo a, b, c;
std::list<int> intList = {1, 2, 3};
std::list<Foo> fooList = {a, b, c};
std::list<Foo *> fooPtrList = {&a, &b, &c};
DerivedFooList derivedFooList = {a, b, c};
DerivedFooPtrList derivedFooPtrList = {&a, &b, &c};
auto localIntCheck = [] (int a) { return a == 1; };
auto localFooCheck = [] (const Foo &a) { return a.check(); };
auto localFooPtrCheck = [] (const Foo *a) { return a->check(); };
some(intList, [] (int a) { return a == 1; });
some(intList, &intCheck);
some(intList, localIntCheck);
some(fooList, [] (const Foo &a) { return a.check(); });
some(fooList, &fooCheck);
some(fooList, localFooCheck);
some(fooList, &Foo::check);
some(fooPtrList, [] (const Foo *a) { return a->check(); });
some(fooPtrList, &fooPtrCheck);
some(fooPtrList, localFooPtrCheck);
some(fooPtrList, &Foo::check);
some(derivedFooList, [] (const Foo &a) { return a.check(); });
some(derivedFooList, &fooCheck);
some(derivedFooList, localFooCheck);
some(derivedFooList, &Foo::check);
some(derivedFooPtrList, [] (const Foo *a) { return a->check(); });
some(derivedFooPtrList, &fooPtrCheck);
some(derivedFooPtrList, localFooPtrCheck);
some(derivedFooPtrList, &Foo::check);
return 0;
}
Beachten Sie, dass, wenn der Wert Art der Sammlung ein Objekt oder Objektzeiger, ich möchte weitergeben können, Zeiger auf eine Member-Funktion als zweites Argument zu some
. Und hier werden die Dinge haarig.
Mein erster Versuch war es wie folgt umzusetzen:
template <class T, class F>
bool some(const T &list, F &&func)
{
for(auto item : list) {
if (func(item)) {
return true;
}
}
return false;
}
template <template<class, class> class T, class U, class V, class W>
bool some(const T<U, V> &list, bool (W::*func)() const)
{
return some(list, [=](U const &t){ return (t.*func)(); });
}
template <template<class, class> class T, class U, class V, class W>
bool some(const T<U *, V> &list, bool (W::*func)() const)
{
return some(list, [=](U const *t){ return (t->*func)(); });
}
... aber es funktioniert nicht, wenn die Sammlung nicht STL Sammlung ist, oder zumindest eine, die beiden Template-Argumente übernimmt. In meinem Beispiel funktioniert die Verwendung von DerivedFooList
oder DerivedFooPtrList
nicht.
Mein zweiter Versuch sah wie folgt aus:
template <class T, class F>
bool some(const T &list, F &&func)
{
for(auto item : list) {
if (func(item)) {
return true;
}
}
return false;
}
template <class T, class U>
bool some(const T &list, bool (U::*func)() const)
{
return some(list, [=](U const &t) { return (t.*func)(); });
}
, die jetzt mit DerivedFooList
funktioniert, aber funktioniert nicht mit std::list<Foo *>
oder DerivedFooPtrList
.
Mein dritte Versuch war:
template <class T, class F>
bool some(const T &list, F &&func)
{
for(auto item : list) {
if (func(item)) {
return true;
}
}
return false;
}
template <class T, class U>
bool some(typename std::enable_if<std::is_class<typename T::value_type>::value, T>::type const &list, bool (U::*func)() const)
{
return some(list, [=](U const &t) { return (t.*func)(); });
}
template <class T, class U>
bool some(typename std::enable_if<std::is_pointer<typename T::value_type>::value, T>::type const &list, bool (U::*func)() const)
{
return some(list, [=](U const *t) { return (t->*func)(); });
}
für die Zeit ignorieren ist, dass dies nur mit Sammlungen funktionieren würde, die ein Mitglied haben value_type
genannt, es immer noch nicht meinem obiges Beispiel nicht erlaubt zu kompilieren. Ich denke (aber bin nicht 100% sicher) der Grund ist, dass es T für die zweiten zwei Versionen von some
für die Fälle nicht ableiten kann, in denen ich es verwenden möchte.
Ich habe sehr hart versucht zu sehen, ob es eine Möglichkeit gibt, was ich will aus C++ 11, und ich vermute, dass es ist, aber ich kann es nicht herausfinden. Ist was ich will, und wenn ja, wie mache ich das?
Nur bis zu C++ 11? Wie wäre es mit C++ 17? –
Ich fürchte, ich kann C++ 17 nicht für dieses Projekt verwenden. – GuyGizmo