Frage

In der Signale Boost-Bibliothek , sie den Operator () sind zu überlasten.

Ist das eine Konvention in C ++? Für Rückrufe usw.?

ich diese haben im Code von einem Mitarbeiter gesehen (die einen großen Schub-Fan sein passiert). Von all der Boost-Güte gibt, hat dies nur für mich zu Verwirrung geführt.

Einsicht nach dem Grund für diese Überlastung?

War es hilfreich?

Lösung

Eines der primären Ziel, wenn Betreiber Überlastung () ist ein Funktor zu erstellen. Ein Funktor wirkt wie eine Funktion, aber es hat die Vorteile, dass es Stateful ist, dh es Daten halten kann seinen Zustand zwischen den Anrufen widerspiegelt.

Hier ist ein einfaches Funktors Beispiel:

struct Accumulator
{
    int counter = 0;
    int operator()(int i) { return counter += i; }
}
...
Accumulator acc;
cout << acc(10) << endl; //prints "10"
cout << acc(20) << endl; //prints "30"

Funktoren sind stark mit generischen Programmierung verwendet. Viele STL-Algorithmen werden in sehr allgemeiner Art und Weise geschrieben, so dass Sie Plug-in können Sie Ihre eigene Funktion / Funktors in den Algorithmus. Zum Beispiel kann der Algorithmus std :: for_each Sie eine Operation für jedes Element eines Bereichs anzuwenden. Es könnte so etwas wie das umgesetzt werden:

template <typename InputIterator, typename Functor>
void for_each(InputIterator first, InputIterator last, Functor f)
{
    while (first != last) f(*first++);
}

Sie sehen, dass dieser Algorithmus sehr allgemein gehalten ist, da sie durch eine Funktion parametrisiert. Durch den Operator () können Sie mit dieser Funktion können Sie entweder einen Funktor oder einen Funktionszeiger verwenden. Hier ist ein Beispiel beide Möglichkeiten zeigt:

void print(int i) { std::cout << i << std::endl; }
...    
std::vector<int> vec;
// Fill vec

// Using a functor
Accumulator acc;
std::for_each(vec.begin(), vec.end(), acc);
// acc.counter contains the sum of all elements of the vector

// Using a function pointer
std::for_each(vec.begin(), vec.end(), print); // prints all elements

In Bezug auf Ihre Frage zu operator () Überlastung, gut ja, es ist möglich. Sie können perfekt einen Funktor schreiben, die mehrere Klammern Operator hat, solange man die Grundregeln der Methode Überlastung achten (zum Beispiel nur auf dem Rückgabetyp Überlastung ist nicht möglich).

Andere Tipps

Es ermöglicht eine Klasse wie eine Funktion zu handeln. Ich habe es in einer Logging-Klasse verwendet, wo der Anruf eine Funktion sein sollte, aber ich wollte den zusätzlichen Vorteil der Klasse.

so etwas wie folgt aus:

logger.log("Log this message");

verwandelt sich in diese:

logger("Log this message");

Viele beantwortet hat, dass es einen Funktor macht, ohne einen großen Grund zu sagen, warum ein Funktor ist besser als eine einfache alte Funktion.

Die Antwort ist, dass ein Funktor Zustand haben kann. Betrachten wir eine Summierfunktion -. Es muss eine laufende Summe halten

class Sum
{
public:
    Sum() : m_total(0)
    {
    }
    void operator()(int value)
    {
        m_total += value;
    }
    int m_total;
};

Ein Funktor ist keine Funktion, so dass Sie es nicht überlasten.
Ihre Mitarbeiter richtig ist aber, dass die Überlastung der Betreiber () wird verwendet, um „functors“ - Objekte, die ähnliche Funktionen aufgerufen werden können. In Kombination mit Vorlagen „funktionsähnliche“ Argumente erwarten dies sehr mächtig sein kann, weil die Unterscheidung zwischen einem Objekt und einer Funktion unscharf wird.

Wie andere Plakate gesagt haben: functors haben einen Vorteil gegenüber Normal Funktionen, dass sie Zustand haben kann. Dieser Zustand kann über eine einzige Iteration verwendet wird oder über mehrere Iterationen (zum Beispiel der Summe aller Elemente in einem Behälter zu berechnen) (zum Beispiel alle Elemente in mehreren Behältern erfüllen bestimmte Kriterien zu finden).

Starten Sie std::for_each verwenden, std::find_if usw. häufiger in Ihrem Code und Sie werden sehen, warum es praktisch ist, die Fähigkeit, den Operator () zu überlasten. Es ermöglicht auch functors und Aufgaben eine klare Rufmethode zu haben, die mit den Namen anderer Methoden in den abgeleiteten Klassen.

in Konflikt werden nicht

Sie auch über die C ++ FAQ Matrix Beispiel . Es gibt gute Einsatzmöglichkeiten für sie zu tun, aber es hängt natürlich davon ab, was Sie versuchen zu erreichen.

Funktoren sind im Prinzip wie Funktionszeiger. Sie werden im Allgemeinen als kopierbar (wie Funktionszeiger) und aufgerufen in der gleichen Weise wie Funktionszeiger vorgesehen. Der Hauptvorteil besteht darin, dass, wenn Sie einen Algorithmus haben, der mit einem Templat-Funktors arbeitet, kann der Funktionsaufruf an operator () inlined werden. Allerdings Funktionszeiger sind nach wie vor gültig functors.

, um die Verwendung von Operator () zu bilden functors in C ++ ist verwandt mit funktionale Programmierung Paradigmen, die in der Regel die Verwendung eines ähnlichen Konzept machen: Verschlüsse .

Eine Kraft, die ich sehen kann, aber dies diskutiert werden kann, ist, dass die Unterschrift des Operators () aussieht und verhält sich genauso auf verschiedene Arten. Wenn wir hatten eine Klasse Reporter, die ein Mitglied Methode Bericht hatte (..) und dann eine andere Klasse Writer, die ein Mitglied Verfahren Schreib hatte (..), würden wir müssen Adapter schreiben, wenn wir beide Klassen verwenden möchten, wie vielleicht eine Template-Komponente aus einem anderen System. Alles, was es kümmern würde auf Strings oder was Sie haben, zu übergeben. Ohne den Einsatz von operator () Überlastung oder spezielle Art Adapter zu schreiben, könnten Sie nicht tun Sachen wie

T t;
t.write("Hello world");

da T hat eine Anforderung, dass es eine Memberfunktion namens schreiben, die etwas implizit gießbaren zu const char * akzeptiert (oder eher const char []). Die Reporter-Klasse in diesem Beispiel nicht, dass, also mit T (ein Template-Parametern) Reporter zu sein, würde nicht kompiliert.

Doch wie weit kann ich diese sehe mit verschiedenen Arten funktionieren würde

T t;
t("Hello world");

aber es bedarf noch ausdrücklich, dass der Typ T hat ein solcher Operator definiert, so dass wir immer noch eine Anforderung an T. Persönlich habe ich nicht denke, es mit functors zu wierd ist, wie sie üblicherweise verwendet werden, aber ich würde lieber sehen andere Mechanismen für dieses Verhalten. In Sprachen wie C # können Sie nur in einem Delegierten übergeben. Ich bin nicht allzu vertraut mit den Mitgliedsfunktionszeigern in C ++, aber ich könnte mir vorstellen, Sie das gleiche Verhalten erzielen könnten es ebenfalls.

Anders als syntaktischen Zucker Verhalten, das ich nicht wirklich sehen die Stärken der Bediener die Ausführung dieser Aufgaben zu überlasten.

Ich bin sicher, es gibt mehr Menschen, die wissentlich bessere Gründe haben als ich, aber ich dachte, ich würde meiner Meinung nach für den Rest von euch auslegen zu teilen.

Ein weiterer Mitarbeiter darauf hingewiesen, dass es sich um eine Art und Weise Funktors Objekte als Funktionen zu verschleiern könnte. Zum Beispiel dieses:

my_functor();

Ist wirklich:

my_functor.operator()();

Damit dies bedeutet:

my_functor(int n, float f){ ... };

Kann verwendet werden, dies auch zu überlasten?

my_functor.operator()(int n, float f){ ... };

Andere Beiträge haben einen guten Job gemacht beschreibt, wie operator () funktioniert und warum kann es nützlich sein.

Ich habe vor kurzem einige Code basieren, bereits sehr umfangreichen Einsatz von Operator macht (). Ein Nachteil dieser Betreiber von Überlastung ist, dass einige IDEs weniger wirksame Instrumente als Folge geworden. In Visual Studio können Sie in der Regel einen Rechtsklick auf einen Methodenaufruf an die Methodendefinition zu gehen und / oder in der Erklärung. Leider ist VS nicht intelligent genug, um Index-Operator () Anrufe. Vor allem in komplexen Code mit überschriebene Operator () Definitionen der ganzen Ort, kann es sehr schwierig sein, herauszufinden, was für Stück Code ausgeführt wird, wo. In mehreren Fällen fand ich hatte ich den Code und Spuren durch sie laufen, was tatsächlich finden lief.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top