Передача функтора с шаблонными параметрами в функцию шаблона - PullRequest
0 голосов
/ 12 января 2019

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

#include <iostream>
#include <functional>
#include <array>

template <const size_t N>
using CVec = std::array<double,N>;

template<const size_t N>
using ode_fun = std::function<CVec<N>(const CVec<N>&)>;

template<const size_t N>
void step( const CVec<N>& x, ode_fun<N> sys)
{
  sys(x);
}

struct foo_t
{
  CVec<2>  operator()( const CVec<2>& x_in)
  {
    CVec<2> xdot;

    std::cout << "x_in: [" << x_in[0] << ", " << x_in[1] << "]\n";

    return xdot;
  }
  CVec<2> x;
};

int main()
{
  foo_t foo;
  foo.x[0] = -.5;
  foo.x[1] = 1.0f;

  CVec<2> x;
  x[0] = 12.0;
  x[1] = 23.2;

  step(x, foo);
}

однако при компиляции я получаю эту ошибку:

temp_arg_subs_fail.cpp: In function ‘int main()’:
temp_arg_subs_fail.cpp:42:14: error: no matching function for call to ‘step(CVec<2>&, foo_t&)’
   step(x, foo);
              ^
temp_arg_subs_fail.cpp:12:6: note: candidate: template<long unsigned int N> void step(CVec<N>&, ode_fun<N>)
 void step( const CVec<N>& x, ode_fun<N> sys)
      ^~~~
temp_arg_subs_fail.cpp:12:6: note:   template argument deduction/substitution failed:
temp_arg_subs_fail.cpp:42:14: note:   ‘foo_t’ is not derived from ‘std::function<std::array<double, N>(const std::array<double, N>&)>’
   step(x, foo);
              ^

Однако это работает:

#include <functional>
#include <iostream>

using my_fn = std::function<int(int, int)>;

void summer(int x, int y, my_fn fn)
{
  std::cout << "summer: " << fn(x,y) << std::endl;
}

struct foo_t
{
  int operator()(int x, int y)
  {
    return x + y + z;
  }    
  int z = 0;    
};

int main ()
{    
  foo_t foo;
  foo.z = 5;    

  summer(3,4,foo);

  return 0;
}

По существу, единственное различие, которое я могу отличить между двумя, состоит в том, что один шаблонизирован, а другой нет. Это потому, что пошаговая функция в первом фрагменте - это всего лишь шаблон, а не экземпляр или что-то еще?

1 Ответ

0 голосов
/ 12 января 2019

Проблема в том, что step() требует ode_fun<N> объект в качестве второго аргумента (то есть std::function<std::array<double, N>(std::array<double, N> const &)>) и N должен быть выведен.

Но если вы передадите foo, это будет foo_t объект, который можно преобразовать в ode_fun<2>, но (это точка) не a ode_fun<2> объект, компилятор не может определить значение N.

Вы можете решить проблему двумя очевидными способами.

(1) передать объект ode_fun<2> в step()

ode_fun<2>  foo2 { foo };

step(x, foo2);

(2) или выведите простой тип F (как «функциональный») в step(), так что все функции выводятся

template<const size_t N, typename F>
void step( const CVec<N>& x, F sys)
{
  sys(x);
}

Это потому, что пошаговая функция в первом фрагменте - это всего лишь шаблон, а не экземпляр или что-то еще?

Точно.

В вашем примере, не являющемся шаблоном, summer() получает std::function<int(int, int)>.

Ничего не нужно выводить, поэтому, передав ему объект foo_t, который не является std::function<int(int, int)>, но может быть преобразован в него, компилятор преобразует foo в std::function<int(int, int)>.

...