C++-Konvertierungsoperator zum Konvertieren in einen Funktionszeiger

Lesezeit: 7 Minuten

C Konvertierungsoperator zum Konvertieren in einen Funktionszeiger
Ken Wayne VanderLinde

Ich zerbreche mir den Kopf gegen eine Idee, die in meinem Kopf einfach genug ist, aber ich kann nicht herausfinden, wie ich sie in C++ implementieren soll.

Normalerweise kann ich eine Klasse mit einem Konvertierungsoperator wie in diesem einfachen Beispiel deklarieren:

class Foo
{
private:

    int _i;

public:

    Foo( int i ) : _i(i) { }

    operator int( ) const
    {
        return i;
    }
};

So kann ich jetzt tolle Sachen schreiben wie

int i = Foo(3);

Aber in meinem speziellen Fall möchte ich einen Operator zum Konvertieren eines Objekts in einen Funktionszeiger bereitstellen (zB Konvertieren von a Bar Instanz zu a int(*)(int, int) Funktionszeiger). Folgendes habe ich anfangs versucht:

class Bar
{
private:

    int (*_funcPtr)(int, int);

public:

    Bar( int (*funcPtr)(int, int) ) : _funcPtr(funcPtr) { }

    operator int(*)(int, int) ( ) const
    {
        return _funcPtr;
    }

};

Die Operatorfunktion kann jedoch nicht kompiliert werden, wobei diese Fehler generiert werden:

expected identifier before '*' token
'<invalid-operator>' declared as a function returning a function

Ich habe auch einfache Variationen des Obigen ausprobiert, beispielsweise den Rückgabetyp in Klammern, aber alle diese Ideen sind ebenfalls gescheitert.

Weiß jemand, wie die Syntax zum Deklarieren einer Konvertierungs-zu-Funktionszeiger-Operatormethode lautet oder ob dies überhaupt möglich ist?

Hinweis: Ich kompiliere dies mit Code::Blocks using GCC 4.5.2. Antworten zu einigen der neuen C++0x-Konzepte sind ebenfalls willkommen.

Bearbeiten

In meinem Bemühen, das Beispiel zu vereinfachen, habe ich versehentlich ein Detail ausgelassen. Es ist ein bisschen seltsam, aber anstatt strikt zurückzugeben int(*)(int,int) -Zeiger soll der Konvertierungsoperator als Vorlage verwendet werden:

template<typename ReturnType, typename ArgType1, typename ArgType2>
operator ReturnType(*)(ArgType1, ArgType2) ( ) const
{
    // implementation is unimportant here
}

Soweit mir bekannt ist, kann ich einen solchen Typ nicht mehr eingeben. Das macht die Sache natürlich viel ungeschickter, aber ich hoffe, dass es noch einen Weg gibt.

  • Versuchen Sie, den Rückgabetyp mit typedef zu definieren: “typedef int (*ptr_t)(int,int);” Geben Sie dann ein Objekt vom Typ “operator ptr_t () const” zurück

    – JT

    20. Juli ’11 um 0:25


  • Ihnen fehlt ein Doppelpunkt. public:

    – Kerrek SB

    20. Juli ’11 um 0:30

  • versuchst du boost::function nachzuahmen?

    – JT

    20. Juli ’11 um 0:37

  • @JT: Ich mache etwas Ähnliches wie boost::function aber es hat ein ganz bestimmtes Verhalten. Ich habe ursprünglich nach der Verwendung gesucht boost::function, aber leider fand ich es nicht die passende Wahl.

    – Ken Wayne VanderLinde

    20. Juli ’11 um 0:54

C Konvertierungsoperator zum Konvertieren in einen Funktionszeiger
Kerrek SB

Da musst du wissen:

(*operator int() const)(int, int)
{
  return _funcPtr;
}

(Behoben. Wieder.)


Aktualisieren: Ich wurde von Johannes Schraub und Luc Danton informiert, dass diese Syntax tatsächlich nicht gültig ist und dass Sie wirklich muss Verwenden Sie eine Typdefinition. Da Sie sagen, dass Typedefs keine Option sind, ist hier eine Hilfsklasse, die Ihre Typedef umschließen kann:

template<typename R, typename A1, typename A2>
struct MakeFunctionType
{
  typedef R(*type)(A1, A2);
};

template<typename R, typename A1, typename A2>
operator typename MakeFunctionType<R, A1, A2>::type () const
{
    // implementation is unimportant here
}

  • das hilft nicht bei dem von ihm erwähnten Vorlagenfall

    – JT

    20. Juli ’11 um 0:54

  • Nein, das war vor der Bearbeitung, aber das sollte einfach sein, um es zu verallgemeinern template<typename R, typename... Args> (*operator T() const)(Args...).

    – Kerrek SB

    20. Juli ’11 um 1:00

  • Vielen Dank. Die Syntax von Funktionszeigern kann manchmal ziemlich verwirrend sein, insbesondere in einem Szenario, das anscheinend nicht viele Leute verwenden und in dem Typedefs nicht anwendbar sind. Bekomme ich eine Chance, eine Erklärung zu bekommen, warum das so aussieht? Meine Idee ist das operator int() const ist der Name der Funktion, daher wird er in Klammern gesetzt und mit einem Sternchen vorangestellt. Dann lassen wir, wie bei Konvertierungsoperatoren üblich, den Rückgabetyp weg, da er bereits Teil des Namens ist. Ist das der richtige Grund für die Syntax?

    – Ken Wayne VanderLinde

    20. Juli ’11 um 1:00

  • Das Grundprinzip ist, dass Sie immer die Kennung des letzten Objekts in Klammern und anhängen die Argumente in einer weiteren Klammer am Ende: Wenn die Funktionssignatur ist R(S, T), dann ist ein Funktionszeiger R(*myfp)(S,T) (und der eigentliche Funktionstyp ist R()(S,T)). Jetzt wenden wir dieses Denken an auf operator A() const mit A = R(*)(S,T) bekommen (*???)(S,T), wo ??? = operator R() const. Denken Sie daran, von “Typ” zu wechseln R” zu “Funktionsrückgabetyp R“.

    – Kerrek SB

    20. Juli ’11 um 1:04

  • Ja, benutze einen Helfer: <template typename R, typename... Arg> struct MakeMyFP { typedef R(*type)(Args...); };, dann sage <template typename R, typename... Args> operator typename MakeMyFP<R,Args...>::type () const.

    – Kerrek SB

    20. Juli ’11 um 1:12


1641932141 454 C Konvertierungsoperator zum Konvertieren in einen Funktionszeiger
Nemo

Verwenden Sie eine Typdefinition. Es ist sowieso einfacher zu lesen:

class Bar
{
public:
  typedef int (*fptr_t)(int, int);

  Bar(fptr_t funcPtr) : _funcPtr(funcPtr) { }

  operator fptr_t() const
  {
    return _funcPtr;
  }

private:
  fptr_t _funcPtr;
};

[edit]

Für Ihren Vorlagenfall sehe ich nicht, wie man eine Typedef verwendet. @Kerrik gibt die (unordentliche) Version der Syntax an, die funktionieren sollte.

  • Angenommen, das obige funktioniert, gibt es eine Möglichkeit ohne Typedef? Nur neugierig; Ich stimme zu, dass die Typedef viel sinnvoller ist.

    – Chris

    20. Juli ’11 um 0:27


  • Hallo, danke für die Antwort. Sie werden sehen, dass ich meine Frage bearbeitet habe, da ich ein kleines, aber sehr wichtiges Detail über meine Verwendung von Vorlagen ausgelassen habe. Könnte ich in diesem Fall immer noch die Einfachheit einer Typedef nutzen?

    – Ken Wayne VanderLinde

    20. Juli ’11 um 0:32

  • @JT – Ich glaube, ich habe meine Antwort 15 Minuten vor deiner gepostet. Auch 5 Sekunden bevor du deinen Kommentar gepostet hast. (Fahren Sie mit der Maus über die Zeiten, um sie in Stunden:Minuten:Sekunden anzuzeigen.)

    – Nemo

    20. Juli ’11 um 1:02


  • @JT und es kann nicht passieren, dass Nemo das einfach beantwortet, ohne deine Antwort vorher gelesen zu haben? Warum gehen Sie davon aus, dass er Ihre Antwort “stiehlt”? Das ist kindisch.

    – Johannes Schaub – litb

    22. Juli ’11 um 22:24

1641932141 777 C Konvertierungsoperator zum Konvertieren in einen Funktionszeiger
JT

BEARBEITEN:

Da Ihrer Klasse bei der Konstruktion ein Nicht-Vorlagenfunktionszeiger zugewiesen wurde:

private:

    int (*_funcPtr)(int, int);

Es ist überhaupt nicht möglich, das später in einen Funktionszeiger irgendeines Typs umzuwandeln.

Ich gehe daher davon aus, dass Sie eine Überladung des Operators für einen Vorlagen-Klassenmember gemeint haben, nicht eine Überladung eines Klassen-Vorlagen-Member-Operators.

Vorlagenversion:

template<typename ReturnType, typename ArgType1, typename ArgType2>
class Bar {

public:

  typedef ReturnType (*fptr_t)(ArgType1, ArgType2);

  operator fptr_t ( ArgType1 arg1, ArgType2 arg2 ) const
  {
      // implementation is unimportant here
  }

//etc...

};

Dann so verwendet:

//create functor to some function called myfunc
Bar::fptr_t func_ptr = Bar<int, int, int>(&myfunc); 

//call functor
int i = func_ptr(1,2); 

  • Dies ist eine Klassenvorlage mit einer Memberfunktion. Es sieht so aus, als ob er eine echte Klasse mit einer Memberfunktionsvorlage haben möchte.

    – Aschepler

    20. Juli ’11 um 0:44

  • @JT: aschepler hat genau recht. Die gleiche Instanz von Bar muss in viele verschiedene Typen von Funktionszeigern konvertierbar sein, daher ist das Erstellen von Vorlagen für die Klasse keine Option. Und wenn es jemand vorschlägt, kann ich auch nicht in einen vorlagenbasierten Funktortyp konvertieren, es muss ein tatsächlicher Funktionszeiger sein.

    – Ken Wayne VanderLinde

    20. Juli ’11 um 0:48

Wenn Sie den Code lesbar machen möchten, müssen um eine Typdefinition zu verwenden. Ich verwende nicht einmal Funktionszeiger, ohne sie zu definieren, die Syntax ist zu schrecklich.

Ziel:

template<typename ReturnType, typename ArgType1, typename ArgType2>
operator ReturnType(*)(ArgType1, ArgType2) ( ) const
{
   return 0;
}

Weg:

// 1: helper structure
template <typename R, typename A0, typename A1>
struct helper {
  typedef R (*type)(A0,A1);
};

// 2: operator
template <typename R, typename A0, typename A1>
operator typename helper<R, A0, A1>::type() const {
  return 0;
}

Schau es dir an ideon!

In C++11 ist es möglich, ein Alias-Vorlage um in eine beliebige Funktion umzuwandeln, ohne dass benutzerdefinierte Typenmerkmale erforderlich sind structS.

class Bar
{
    private:


    template<typename ReturnType, typename ArgType1, typename ArgType2>
    using funcptr = ReturnType(*)(ArgType1, ArgType2);

    public:

    template<typename ReturnType, typename ArgType1, typename ArgType2>
    operator funcptr<ReturnType, ArgType1, ArgType2> ( ) const;

};

Um dies auf nur zu beschränken int(*)(int, int), wir können SFINAE verwenden oder static_assert.

C Konvertierungsoperator zum Konvertieren in einen Funktionszeiger
Vladimir Reshetnikov

Folgendes funktioniert in GCC:

template<typename ReturnType, typename ArgType1, typename ArgType2>
operator decltype((ReturnType(*)(ArgType1, ArgType2)) nullptr)() const
{
    // ...
}

.

385550cookie-checkC++-Konvertierungsoperator zum Konvertieren in einen Funktionszeiger

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy