передача пакета параметров по сигнатуре устаревшей функции с использованием forward_as_tuple

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

#include <tuple>
#include <cassert>

void LegacySignature( void* param );

template< typename... ArgsT >
// using ???; // attempt: can 'template alias' or 'using declaration' make the pack's type visible so I can use it inside the LegacyFunction?
void MyFunc( ArgsT&... args )
{
  auto userArgsTuple = std::forward_as_tuple< ArgsT&... >( args... );

  LegacySignature( &userArgsTuple );
}

void LegacySignature( void* param )
{
//  auto userArgsTuple = reinterpret_cast<???>( param ); // attempt: how can I get the parameter pack's type declared so I can use it here?

  // do something with the params like change num to 44 and tf to true;
  //userArgsTuple->num = 44; // desired functionality
  //userArgsTuple->tf = true; // desired functionality
}

int main()
{
  int num { 33 };
  bool tf { false };
  MyFunc( num, tf );
  assert( num == 44 && tf == true );

  return 0;
}

Есть ли способ сделать пакет параметров декларируемым lvalue?


person rtischer8277    schedule 13.12.2016    source источник
comment
Как догадка, они хотят, чтобы вы передали обратный вызов. Обратный вызов принимает void* и некоторые другие аргументы, которые они предоставляют. Вы хотите передать некоторые данные через void*, чтобы они были переданы вам на другом конце. Они не будут хранить ваш обратный вызов или ваш void* дольше, чем фиксированная область, над которой вы имеете контроль. Это верно? Вопрос: void* передается в качестве первого или последнего параметра вашей функции обратного вызова?   -  person Yakk - Adam Nevraumont    schedule 14.12.2016
comment
Использование void* было просто моей попыткой представить фактическую подпись как нейтральный тип для обсуждения. На самом деле фактическим параметром подписи является почтенный LPARAM, который является long. Как заявляет MS, и WPARAM, и LPARAM являются «типами, используемыми для передачи и возврата полиморфных значений». Таким образом, в моем вопросе не передаются и не вызываются обратные вызовы. Мой интерес заключается непосредственно в лучшем понимании того, как пересылать произвольное количество аргументов через такую ​​устаревшую конструкцию, где эти параметры являются ссылками с изменяемым значением в интеллектуальном указателе.   -  person rtischer8277    schedule 14.12.2016
comment
К вашему сведению, я решил проблему обратных вызовов поверх устаревших подписей, используя future См. проблему StackOverflow [Как я могу использовать shared_ptr с помощью PostThreadMessage?]( stackoverflow.com/questions /25667226) и найдите ответ, начинающийся с @Remy Lebeau и @rtischer8277 уже отправили два ответа на мое первоначальное сообщение….   -  person rtischer8277    schedule 14.12.2016


Ответы (2)


Я предполагаю, что вам нужен указатель функции на вашу устаревшую подпись.

Вот подход С++ 11.

template<class Sig, class F>
struct magic_callback_t;

template<class R, class...Args, class F>
struct magic_callback_t<R(Args...), F> {
  F f;
  void* pvoid() const { return this; }
  using result_sig = R(*)(void*, Args...);
  result_sig pfunc() const {
    return [](void* pvoid, Args...args)->R{
      auto* self = static_cast<magic_callback_t*>(pvoid);
      return (self->f)(std::forward<Args>(args)...);
    };
  }
};
template<class Sig, class F>
magic_callback_t<Sig, F> magic_callback( F&& f ) {
  return {std::forward<F>(f)};
}

Теперь мы просто делаем это:

auto callback = magic_callback( [&](){
  // use whatever as if we where in the enclosing scope
});

void(*)(void*) legacy_ptr = callback.pfunc();
legacy_ptr( callback.pvoid() );

вызовет лямбду, которую вы передали magic_callback.

Если вы хотите хранить данные в виде кортежа, вы можете это сделать. Просто захватите кортеж в лямбда-выражении, а затем используйте std::get для доступа к нему в теле лямбда-выражения. Используйте mutable, если вы хотите, чтобы он был изменчивым.

person Yakk - Adam Nevraumont    schedule 13.12.2016
comment
Отличное решение для обратного звонка. Моя основная потребность, однако, состоит в том, чтобы переключать потоки, синхронно выполнять существующую функцию в целевом потоке, возможно, с переданными параметрами, и синхронно возвращать значения. Мое решение SendThreadMessage, на которое я вам указал, делает это, за исключением передачи нескольких параметров. Подход с передачей произвольных параметров по ссылке, описанный в примере кода, является лучшим решением. Решения обратного вызова, к сожалению, асинхронны. Я всегда мог передать необработанный ptr уникальному или общему объекту, но это затруднило бы работу разработчиков вызывающих абонентов. - person rtischer8277; 14.12.2016

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

#include <tuple>
#include <cassert>
#include <memory>
#include <functional>

#define ARGSET int, bool

void LegacySignature( long* param ); // ie, LPARAM

template< typename... ArgsT >
struct MyParams
{
  MyParams( ArgsT... args ) : rvalRefs { std::forward_as_tuple( args... ) } {} // The resulting forward_as_tuple tuple has rvalue reference data members 
  std::tuple< ArgsT... > rvalRefs;
};


void LegacySignature( long* legSigParam )
{
  auto userArgsTuple( reinterpret_cast< MyParams< ARGSET >* >( legSigParam ) );

  // do something with the params like change num to 44 and tf to true;
  std::get< 0 >( userArgsTuple->rvalRefs ) = 44; // index types can probably be worked out using enums
  std::get< 1 >( userArgsTuple->rvalRefs ) = true;
}

int main()
{
  int num { 33 };
  bool tf { false };
  MyParams< ARGSET > myParams( num, tf );

  std::unique_ptr< MyParams< ARGSET > > legSigParamPtr = std::make_unique< MyParams< ARGSET > >( myParams );
  LegacySignature( ( long* )legSigParamPtr.get() );
  assert( std::get< 0 >( legSigParamPtr->rvalRefs ) == 44 && std::get< 1 >( legSigParamPtr->rvalRefs ) == true );

  return 0;
}
person rtischer8277    schedule 15.12.2016