Comment gérer les méthodes anonymes Delphi dans C++

De RAD Studio
Aller à : navigation, rechercher

Remonter à Gestion des fonctionnalités Delphi dans C++Builder - Index


Cette rubrique décrit comment gérer les méthodes anonymes Delphi dans le code C++.

Implémentation des types de méthode anonyme Delphi

Delphi implémente les types de méthodes anonymes (aussi connus comme des références de méthode) via une interface qui implémente une méthode Invoke(...).

Ainsi une méthode qui prend un paramètre référence de méthode dans Delphi est exposée dans C++ comme une méthode qui prend une interface. Par exemple :

interface

type
    TFilterPredicate = reference to function(const Path: string;
        const SearchRec: TSearchRec): Boolean;
// …

class function GetFiles(const Path: string; const Predicate: TFilterPredicate):
    TStringDynArray; overload; inline; static;

Le code suivant est le fichier d'en-tête C++ fourni par RAD Studio pour l'exemple ci-dessus :

typedef System::DelphiInterface<TFilterPredicate> _di_TFilterPredicate;
__interface TFilterPredicate  : public System::IInterface 
{
    virtual bool __fastcall Invoke(const System::UnicodeString Path,
        const System::Sysutils::TSearchRec &SearchRec) = 0 ;
};
// …
static System::TStringDynArray __fastcall GetFiles(const System::UnicodeString
    Path, const _di_TFilterPredicate Predicate)/* overload */;

Comme illustré ci-dessus, TFilterPredicate est exposé sous la forme d'une interface côté C++. Le code C++ qui effectue une opération seek pour spécifier une fonction ou une fonction membre comme paramètre référence de méthode doit envelopper la dernière derrière une interface qui expose la méthode Invoke().

Gestion des types de méthode anonyme dans C++

Utilisation d'une expression lambda

Si vous utilisez un compilateur C++ amélioré par Clang, vous pouvez utiliser une expression lambda chaque fois qu'une API Delphi attend une méthode anonyme Delphi. La classe DelphiInterface s'auto-convertit automatiquement en expression lambda.

Par exemple :

#include <System.hpp>
#include <System.IOUtils.hpp>
#include <iostream>
 
int main()
{
  String ext(".cpp");                   
  TStringDynArray files = TDirectory::GetFiles(TDirectory::GetCurrentDirectory(),
                          [ext](const String Path, const System::Sysutils::TSearchRec &SearchRec) -> bool
                          {
                            return ExtractFileExt(SearchRec.Name) == ext;
                          });
  std::cout << "Found " << files.Length 
            << " files with ext: '" << AnsiString(ext).c_str() << "'\n";
  for (int i=0; i<files.Length; ++i)
    std::cout << AnsiString(files[i]).c_str() << std::endl;
}

Utilisation d'un foncteur (objet fonction)

Un template C++ peut être utilisé pour l'encapsulation d'une interface qui expose une méthode Invoke().

Le code C++ suivant montre un exemple d'un template qui peut être utilisé pour transmettre des fonctions membre ou des méthodes C++ en tant que références de méthode à Delphi :

#include <System.hpp>
 
enum _DummyType{};      // Parameter used as default
 
template <typename INTF, // Interface with Invoke
          typename F,    // Functor type
          typename R,    // Return type
          typename P1 = _DummyType,  // Param #1
          typename P2 = _DummyType,  // Param #2
          typename P3 = _DummyType,  // Param #3
          typename P4 = _DummyType,  // Param #4
          typename P5 = _DummyType>  // Param #5
class TMethodRef : public TCppInterfacedObject<INTF>
{
private:
  F callback;
public:
  TMethodRef(F _callback) : callback(_callback) {}
  INTFOBJECT_IMPL_IUNKNOWN(TInterfacedObject);
 
  R __fastcall Invoke(P1 p1) {
    return callback(p1);
  }
  R __fastcall Invoke(P1 p1, P2 p2) {
    return callback(p1, p2);
  }
  R __fastcall Invoke(P1 p1, P2 p2, P3 p3) {
    return callback(p1, p2, p3);
  }
  R __fastcall Invoke(P1 p1, P2 p2, P3 p3, P4 p4) {
    return callback(p1, p2, p3, p4);
  }
  R __fastcall Invoke(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
    return callback(p1, p2, p3, p4, p5);
  }
};

Le code suivant vous montre comment utiliser le modèle affiché ci-dessus pour appeler GetFiles :

#include <System.IOUtils.hpp>
#include <iostream>
 
struct Filter {
  Filter(String _ext) : ext(_ext)
  {}
  bool operator()(const System::UnicodeString, const System::Sysutils::TSearchRec &SearchRec) {
    return ExtractFileExt(SearchRec.Name) == ext;
  }
  String ext;
};
 
int main()
{
  typedef TMethodRef<TDirectory::TFilterPredicate,
                     Filter,
                     bool,
                     const System::UnicodeString,
                     const System::Sysutils::TSearchRec&> MyMethRef;
  String ext(".cpp");                   
  TStringDynArray files = TDirectory::GetFiles(TDirectory::GetCurrentDirectory(),
                          TDirectory::_di_TFilterPredicate(new MyMethRef(Filter(ext))));
  std::cout << "Found " << files.Length 
            << " files with ext: '" << AnsiString(ext).c_str() << "'\n";
  for (int i=0; i<files.Length; ++i)
    std::cout << AnsiString(files[i]).c_str() << std::endl;
}

Voir aussi