c++delphic++builder-xe8

Embarcadero TThread: Pass TThreadMethod in C++


Edit: Now that I have a better idea of what is going on, I think I can better phrase this question so it is more useful.

I am trying to replicate the following delphi code in C++

TThread.Queue(nil, 
    procedure
    begin
        LogMessage("test");
    end
    );

The purpose of the code is to call a method which updates a TMemo on a form in a thread safe manner. Here is the C++ version of the method I am trying to call with Thread.Queue

void __fastcall TClientForm::LogMessage( String message )
{
    MemoLog->Lines->Add( message );
}

Because I am using a BCC32 compiler without CLANG enhancements, using a Lambda is not an option. Instead according to this documentation I need to create a class which inherits from TThreadProcedure which overrides the Invoke() method to do the work I need done. Then I can pass an instance of that class into TThread::Queue.

I created the following class which inherits TThreadProcuedure and contains an invoke method.

class TMyThreadProcedure : TThreadProcedure
{
    void __fastcall Invoke( String message );
};

However, since TThreadProcedure is an abstract class, I cannot simply create an instance of it to pass into TThread::Queue. What is the proper way to inherit from TThreadProcedure and define a function to be called when I pass an instance of my class into TThread::Queue?


Solution

  • As stated in the documentation:

    How to Handle Delphi Anonymous Methods in C++

    You have two choices:

    1. derive a class 1 that implements the appropriate interface (in this case, Classes::TThreadProcedure), overriding the Invoke() method to do your desired work. You can then pass an instance of that class to TThread::Queue(). For example:

      class TLogMessageRef : public TCppInterfacedObject<Classes::TThreadProcedure>
      {
      private:
          TClientForm *form;
      public:
          TLogMessageRef(TClientForm* _form) : form(_form) {}
          INTFOBJECT_IMPL_IUNKNOWN(TInterfacedObject);
      
          void __fastcall Invoke()
          {
              form->LogMessage("test");
          }
      };
      
      TThread::Queue(NULL,
          Classes::_di_TThreadProcedure(
              new TLogMessageRef(this)
          )
      );
      

      (1 the use of TCppInterfacedObject and INTFOBJECT_IMPL_IUNKNOWN is covered elsewhere in the documentation: Inheritance and Interfaces)

      The documentation also provides a reusable TMethodRef class to help with the implementation, if you need to use anonymous methods/procedures in multiple places of your code:

      Using a Functor (Function Object)

      For example:

      struct LogMsg
      {
          TClientForm* form;
          LogMsg(TClientForm *_form) : form(_form) {}
          void operator()()
          {
              form->LogMessage("test");
          }
      };
      
      typedef TMethodRef<Classes::TThreadProcedure, LogMsg, void> MyMethRef;
      
      TThread::Queue(NULL,
          Classes::_di_TThreadProcedure(
              new MyMethRef(
                  LogMsg(this)
              )
          )
      );
      
    2. in the Clang-based C++11 compilers only, you can use a C++ lambda anywhere an anonymous procedure/method is expected:

      TThread::Queue(NULL, 
          [this]() -> void { LogMessage("test"); }
      );