Использование std::apply в методе класса

Я пытаюсь скомпилировать следующее (g++-11.2, C++20), но получаю:

      error: no matching function for call to '__invoke(std::_Mem_fn<void (Foo::*)(int, double)>, std::__tuple_element_t<0, std::tuple<int, double> >, std::__tuple_element_t<1, std::tuple<int, double> >)'
 1843 |       return std::__invoke(std::forward<_Fn>(__f),

Код:

      #include <iostream>
#include <tuple>

struct Foo
{
    void bar(const int x, const double y) 
    {  
        std::cout << x << " " << y << std::endl;
    }  


    void bar_apply()
    {  
        // fails
        std::apply(std::mem_fn(&Foo::bar), std::tuple<int, double>(1, 5.0));
    }  
};


int main()
{
    Foo foo;
    foo.bar_apply();
};

3 ответа

Решение

Я рекомендую использовать C++20 bind_front, который более легкий и интуитивно понятный. Как и его имя, функции-члены требуют вызова определенного объекта класса, поэтому вам нужно привязать this указатель на Foo::bar.

      void bar_apply()
{  
  std::apply(std::bind_front(&Foo::bar, this), std::tuple<int, double>(1, 5.0));
}

Демо.

std::mem_fn(&Foo::bar) не хранит экземпляр Foo как это сделала бы лямбда:

      std::apply([this](int x, double y) { return bar(x,y); },
           std::tuple<int, double>(1, 5.0));

Поэтому вам необходимо предоставить экземпляр при вызове mem_fn объект:

      std::apply(std::mem_fn(&Foo::bar), std::tuple<Foo*, int, double>(this, 1, 5.0));

или проще, используя make_tuple:

      std::apply(std::mem_fn(&Foo::bar), std::make_tuple(this, 1, 5.0));

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

Однако я бы посоветовал std::invoke, который больше подходит для этой задачи. Таким образом, обертывание экземпляра не требуется.

      #include <functional> // std::invoke

std::invoke(&Foo::bar, this, 1, 5.0);
Другие вопросы по тегам