На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Cконвертировать замыкание со списком захвата в указатель на функцию С++14 , Что то не выходит никак
    Всем привет.
    В общем - надо сделать вот так вот:
    ExpandedWrap disabled
      class TestTimer
      {
      public:
          TestTimer()
          {
              auto callback = [&](PVOID pvContext, BOOLEAN fTimeout) { std::cout << "Ky ky member: " << ++m_member; };
              CreateTimerQueueTimer(&m_hTimer, NULL, callback, NULL, 10000, 5 * 1000, 0);
          }
          ~TestTimer()
          {
              DeleteTimerQueueTimer(NULL, m_hTimer, NULL);
          }
       
      private:
          HANDLE m_hTimer;
          int m_member;
      };
       
      int main()
      {
         TestTimer timer_quard;
       
         std::cin.get();
      }

    Но так не работает. Если убрать из списка захвата ссылку - все норм конвертируется. Как я понимаю без списка захвата конвертируется норм по стандарту? А если мне надо со списком захвата, то как? :huh:
    Сообщение отредактировано: KILLER -
      Цитата KILLER @
      А если мне надо со списком захвата, то как?

      Никак. Лямбды со списком захвата не кастуются к указателям на функцию.

      У CreateTimerQueueTimer есть параметр:

      Parameter [in, optional]
      A single parameter value that will be passed to the callback function.

      Использую его.
        Т.е. если убрать ссылку из списка захвата - все компилируется и работает просто супер пупер. А со списком никак (( :unsure:

        Добавлено
        Цитата XandoX @
        Никак. Лямбды со списком захвата не кастуются к указателям на функцию.

        Вообще никак не кастуются? Может как то через std::function можно такое провернуть?
          Цитата KILLER @
          Вообще никак не кастуются? Может как то через std::function можно такое провернуть?

          Нет. Через std::function тоже не получиться.

          Почему так происходить, можно понять из того как что лямбды на самом деле это локально сгенерированные классы с operator(). Для лябмды с со списком захвата, нужно иметь контекст, который неявно передается через this, для лямбд без списка захвата, this не нужен и operator() вообще может быть статическим. И вот указатель на статический operator() и передается как указатель на функцию.
          Это вообще конечно все достаточно вольное объяснение, но все примерно так и работает.
            Ясно, это пичально блин, придется структуру заводить, потому как мне там на самом деле не один мембер надо передавать, думал отделаться парой строчек. Ну ладно тогдаЮ буду через параметр таймера передавать.
            Спасибо.
              Цитата KILLER @
              Ясно, это пичально блин, придется структуру заводить, потому как мне там на самом деле не один мембер надо передавать, думал отделаться парой строчек.
              Ну а кто не даёт сделать типа того:
              ExpandedWrap disabled
                class TestTimer
                {
                public:
                    TestTimer()
                    {
                        auto callback = [](PVOID pvContext, BOOLEAN fTimeout) { std::cout << "Ky ky member: " << ++reinterpret_cast<TestTimer*>(pvContext)->m_member; };
                        CreateTimerQueueTimer(&m_hTimer, NULL, callback, this, 10000, 5 * 1000, 0);
                    }
                    ~TestTimer()
                    {
                        DeleteTimerQueueTimer(NULL, m_hTimer, NULL);
                    }
                 
                private:
                    HANDLE m_hTimer;
                    int m_member;
                };
                Цитата Qraizer @
                Ну а кто не даёт сделать типа того:

                Я примерно так и сделал, только пришлось делать и передавать кортеж. Я хз на сколько это верный подход. У меня получается вот этот класс TestTimer содержит приватные поля: 1) мьютекс, который нужно передать в нутрь лямбды, 2) мапу объектов, которая тоже закрытая и которую тоже надо передать в лямбду. В итоге получилось что то типа того:
                ExpandedWrap disabled
                  class TestTimer
                  {
                  public:
                      TestTimer()
                      : m_member1(10),
                        m_member2(20)
                      {
                          m_Tuple = std::make_tuple(&m_member1, &m_member2, this);
                          auto callback = [](PVOID pvContext, BOOLEAN fTimeout)
                          {
                              using TTupleArgs = std::tuple<int*, int*, TestTimer*>;
                              TTupleArgs args = *((TTupleArgs*)(pvContext));
                   
                              int& arg1 = *std::get<0>(args);
                              int& arg2 = *std::get<1>(args);
                              TestTimer* arg3= std::get<2>(args);
                   
                              std::cout << "Arg1: "  << arg1 << " Arg2: " << arg2 << std::endl;
                   
                              arg3->print();
                   
                              ++arg1;
                              ++arg2;
                          };
                          CreateTimerQueueTimer(&m_hTimer, NULL, callback, &m_Tuple, 1000, 5 * 1000, 0);
                      }
                      void print()
                      {
                          std::cout << "Yo yo1: " << m_member1 << " Yo yo2: " << m_member2 << std::endl;
                      }
                      ~TestTimer()
                      {
                          DeleteTimerQueueTimer(NULL, m_hTimer, NULL);
                      }
                   
                  private:
                      HANDLE m_hTimer;
                      int m_member1; //! на самом деле Mutex
                      int m_member2; //! На самом деле какой нибудь std::map<std::string, SomeObject>
                      std::tuple<int*, int*, TestTimer*> m_Tuple;
                  };

                Или в принципе такое имеет право на жизнь? Мне кажется как то всеравно громоздко вышло? Может как то проще сделать можно?
                Сообщение отредактировано: KILLER -
                  Ты можешь разделить callback от таймера и имплементацию callback-а

                  будет красивше, ИМХО (Ну я исхожу еще из своего правила, что лямбда длиннее 3 строк, что-то неправильное)

                  ExpandedWrap disabled
                    class TestTimer
                    {
                    public:
                        TestTimer()
                        : m_member1(10),
                          m_member2(20)
                        {
                            auto callback = [](PVOID pvContext, BOOLEAN fTimeout)
                            {
                                reinterpret_cast<TestTimer*>(pvContext)->timerCallbackHandler();
                            };
                            CreateTimerQueueTimer(&m_hTimer, NULL, callback, this, 1000, 5 * 1000, 0);
                        }
                        void print()
                        {
                            std::cout << "Yo yo1: " << m_member1 << " Yo yo2: " << m_member2 << std::endl;
                        }
                        ~TestTimer()
                        {
                            DeleteTimerQueueTimer(NULL, m_hTimer, NULL);
                        }
                    private:
                        void timerCallbackHandler()
                        {
                            std::cout << "m_member1: "  << m_member1 << " m_member2: " << m_member2 << std::endl;
                     
                            print();
                     
                            ++m_member1;
                            ++m_member2;
                        }
                     
                    private:
                        HANDLE m_hTimer;
                        int m_member1; //! на самом деле Mutex
                        int m_member2; //! На самом деле какой нибудь std::map<std::string, SomeObject>
                        std::tuple<int*, int*, TestTimer*> m_Tuple;
                    };
                    Да, кстати так лучше. Что то я об этом даже не подумал, с какими то кортежами извращался тут. Спасибо. :blush:
                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                    0 пользователей:


                    Рейтинг@Mail.ru
                    [ Script execution time: 0,0346 ]   [ 16 queries used ]   [ Generated: 19.04.24, 08:28 GMT ]