Использование std::function и bind для назначения функций с разными списками аргументов

Я пытаюсь иметь указатель функции, где в некоторых случаях ему либо назначается функция, принимающая 2 аргумента (cv::Mat и структура, содержащая параметры), либо другая функция, которая принимает 3 аргумента (те же 2 аргументы и список координат). Я полагаю, что std::function и std::bind - это то, что я должен использовать здесь.

Mat process_F1(cv::Mat img, feature_params f);
Mat process_F1_coords(cv::Mat img, feature_params f, std::vector<std::pair<int, int> > feature_coords c);
Mat process_F2(cv::Mat img, feature_params f);
Mat process_F2_coords(cv::Mat img, feature_params f, std::vector<std::pair<int, int> > feature_coords );
// this is the function pointer that will hold them
std::function<cv::Mat()> feature_func_f;
//this is how I assign them:
void set_feature_func(int feature_method, bool use_coords)
{
    switch (feature_method){
    case 0:
            if( !use_coords )
                feature_func_f = std::bind(process_F1,std::placeholders::_2);
            else
                feature_func_f = std::bind(process_F1_coords,std::placeholders::_3);  
            break;
        case 1:
            if( !use_coords )
                feature_func_f = std::bind(process_F2,std::placeholders::_2);
            else
                feature_func_f = std::bind(process_F2_coords,std::placeholders::_3);   
            break;
}

Я намерен вызвать feature_func_f как:

cv::Mat m, n;
feature_params p;
set_feature_func(0,false);

n = feature_func_f(m,p);

// or if I have a coordinate list c
std::vector<std::pair<int, int> > c;

set_feature_func(0,true);
n = feature_func_f(m,p,c);

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

Error   4   error C2977: 'std::add_reference' : too many template arguments C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\functional   900 1   
Error   5   error C2955: 'std::add_reference' : use of class template requires template argument list   C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\functional   900 1   
Error   6   error C2198: 'cv::Mat (__cdecl *)(cv::Mat,feature_params)' : too few arguments for call C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\functional   1149    1   
Error   2   error C2146: syntax error : missing ',' before identifier 'type'    C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\functional   900 1   
Error   3   error C2065: 'type' : undeclared identifier C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\functional   900 1   
Error   1   error C2027: use of undefined type 'std::tuple_element<0x01,_Ftuple>'   C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\functional   900 1   

person Hal T    schedule 13.07.2015    source источник
comment
Удалите вещи, которые не влияют на ваш вопрос, например Matcher::, и пусть он скомпилирует и сгенерирует ошибку сам по себе. Пожалуйста, публикуйте каждую ошибку или хотя бы первый набор ошибок (ошибки, которые начинаются сверху и заканчиваются той частью, где упоминается ваш код) -- a случайный выбор ошибок не так уж и полезен. Подождите секунду, как вы думаете, _2 и _3 - это количество заполнителей? Вы когда-нибудь успешно использовали std::placeholders? Как вы собираетесь вызвать feature_func_f?   -  person Yakk - Adam Nevraumont    schedule 13.07.2015
comment
Я подчистил вопрос и уточнил, как я буду вызывать функцию.   -  person Hal T    schedule 13.07.2015


Ответы (2)


Нет, ты не можешь делать то, что хочешь. std::bind предназначен только для связывания аргументов, которые не следует использовать в вызове функции. Вы можете либо использовать 2 функции, одну для 2 параметров и одну для 3 параметров, либо отправить координаты функции set_feature_func.

Простой пример использования std::function и std::bind.

#include <functional>
#include <iostream>

int main()
{
   std::function<void(int)> function;
   auto l1 = [](int v) { std::cout << v << std::endl; };
   auto l2 = [](int v1, int v2) { std::cout << v1 << " " << v2 << std::endl; };
   function = l1;
   function(5);
   function = std::bind(l2, std::placeholders::_1, 10);
   function(5);
}

И ваш код должен быть похож

std::function<cv::Mat(cv::Mat, feature_params)> feature_func_f;

// coords is vector<vector<...>>
void set_feature_func(int feature_method, coords)
{
   // switch
      if (coords.empty())
      {
         feature_func_f = process_f1;
      }
      else
      {
         feature_func_f = std::bind(process_f1, _1, _2, coords);
      }
}

Применение

std::vector<std::pair<int, int> > c;

set_feature_func(0,true,c);
n = feature_func_f(m,p);
person ForEveR    schedule 13.07.2015

Как правило, тип переменной определяет, какие операции можно выполнять с этой переменной.

feature_func_f имеет один тип. Предыдущий вызов функции не может изменить свой тип.

std::function поддерживает одну подпись аргумента.

Таким образом, n = feature_func_f(m,p); и n = feature_func_f(m,p,c); не могут одновременно быть действительными на std::function.

Есть способы обойти это, но в этом случае нет особого смысла. Имейте два feature_func_f, каждый с разной подписью, и вызывайте правильный.

std::function<cv::Mat(cv::Mat img, feature_params f)> feature_func_f;
std::function<cv::Mat(cv::Mat img, feature_params f, std::vector<std::pair<int,int>>)> feature_func_vector_f;
person Yakk - Adam Nevraumont    schedule 13.07.2015