Извлечение параметра из функции, переданной в качестве параметра - PullRequest
0 голосов
/ 29 июня 2019

У меня есть следующая функция:

void Class1::MainThreadFunction(const __int64 param) {
    if(GetCurrentThreadId() != System::MainThreadID) {
        RunInMainThread(MainThreadFunction, param);
        return;
    }
    //...
}

void Class2::RunInMainThread(void(__closure* FuncToCall)(const __int64 ParToExtract),
                             const __int64 fP1) {
    struct {
        __int64 P1;
        void(__closure* F)(const __int64);

        void __fastcall FTC() { F(P1); }
    } Args = {fP1, FuncToCall};

    TThread::Synchronize(NULL, &Args.FTC);
}

Итак, я пытаюсь извлечь первый параметр в FuncToCall с именем ParToExtract, который будет использоваться для инициализации * 1006.* состав.Другими словами, P1 в структуре должен получить const __int64 от переданной функции, которая названа как ParToExtract.

. Вышеописанное работает, но я в настоящее время в качестве обходного пути передаю параметр как fP1который я использую для инициализации P1, но наверняка должен быть лучший способ сделать это.

Дополнительным бонусом было бы наличие переменного числа параметров функции в RunInMainThread (но на данный момент у меня естьизбегайте C ++ 11 <functional>).

Пожалуйста, не используйте лямбда (или функции C ++ 11) - это еще одна вещь, которую я пока не могу использовать.

Ответы [ 2 ]

3 голосов
/ 30 июня 2019

То, что у вас уже есть, является правильным (и единственным) способом решения этой ситуации в «классических» (до C ++ 11) компиляторах C ++ Builder.

Чтобы поддерживать переменное количество параметров, вам придется использовать несколько перегрузок, другого варианта нет (без погружения в низкоуровневую встроенную сборку для настройки стеков вызовов вручную, но даже в этом случае он может работать некорректно во всех границы потоков), например:

void Class1::MainThreadFunction()
{
    if (GetCurrentThreadId() != System::MainThreadID)
    {
        RunInMainThread(MainThreadFunction);
        return;
    }
    //...
}

void Class1::MainThreadFunction(const __int64 param)
{
    if(GetCurrentThreadId() != System::MainThreadID)
    {
        RunInMainThread(MainThreadFunction, param);
        return;
    }
    //...
}

// and so on as needed ...
template<typename FuncType>
void Class2::RunInMainThread(FuncType FuncToCall)
{
    struct {
        FuncType F;
        void __fastcall FTC() { F(); }
    } Args = {FuncToCall};

    TThread::Synchronize(NULL, &Args.FTC);
}

template<typename FuncType, typename ParamType>
void Class2::RunInMainThread(FuncType FuncToCall, const ParamType param)
{
    struct {
        const ParamType &P;
        FuncType F;
        void __fastcall FTC() { F(P); }
    } Args = {param, FuncToCall};

    TThread::Synchronize(NULL, &Args.FTC);
}

template<typename FuncType, typename ParamType1, typename ParamType2>
void Class2::RunInMainThread(FuncType FuncToCall, const ParamType1 param1, const ParamType2 param2)
{
    struct {
        const ParamType1 &P1;
        const ParamType2 &P2;
        FuncType F;
        void __fastcall FTC() { F(P1, P2); }
    } Args = {param1, param2, FuncToCall};

    TThread::Synchronize(NULL, &Args.FTC);
}

// and so on as needed...

Если вы просматриваете различные заголовочные файлы RTL, такие как sysvari.h и utilcls.h, использование перегрузок - это то, как сама Borland подходит к вопросу о переменном количестве параметров в нескольких своих собственных API, иногда свыше 30+ параметров, этого более чем достаточно для обработки большинства пользовательских кодов.

3 голосов
/ 29 июня 2019

Подпись для метода, вызываемого TThread::Synchronize(), должна соответствовать типу TThreadMethod:

void __fastcall (__closure *TThreadMethod)(void);

, поэтому вы не можете напрямую передавать параметры через него.Вместо того, чтобы использовать прокси-функцию, используйте лямбду:

void MainThreadFunction(int64_t param) {
    if(GetCurrentThreadId() != System::MainThreadID)
        TThread::Synchronize(nullptr, [&param]{ MainThreadFunction(param); } );
    //...
}

Чтобы иметь переменное число параметров, вы можете сделать его шаблоном функции:

template< class... Args >
void MainThreadFunction(Args&&... args) {
    if(GetCurrentThreadId() != System::MainThreadID)
        TThread::Synchronize(nullptr, [&args...] {
                MainThreadFunction(std::forward<Args>(args)...); 
            }
        );
    //...
}

При использованииклассический (до C ++ 11) компилятор, вы обычно используете закрытую переменную класса для переноса информации.

...