Передача вариантов сложной функции в качестве аргументов - PullRequest
3 голосов
/ 02 февраля 2012

Скажем, у меня есть следующая функция шаблона:

template <class T>
void apply(const vector<complex<T> >& in, vector<T>& out, T (*f)(complex<T>))
{
    out.resize(in.size());
    for(size_t i = 0; i < in.size(); ++i) out[i] = f(in[i]);
}

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

Моя проблема в том, как передать функцию?

Я попробовал варианты apply(in, out, abs) с различными шаблонами для abs, но безуспешно. Я почти уверен, что проблема связана с функциями для всех сложных шаблонов, но я не уверен, как это правильно передать. Спасибо за помощь.

Ответы [ 2 ]

4 голосов
/ 02 февраля 2012

Проблема в том, что std::abs (из <complex>) принимает параметр std::complex<T> в качестве ссылки на постоянное значение. Указатель вашей функции говорит только по значению, что вызывает несоответствие. Следующий код компилируется просто отлично:

#include <vector>
#include <complex>

template <class T>
void apply(const std::vector<std::complex<T> >& in, std::vector<T>& out,
           T (*f)(std::complex<T> const&))
{
    out.resize(in.size());
    for(size_t i = 0; i < in.size(); ++i)
      out[i] = f(in[i]);
}

int main(){
  std::vector<std::complex<float> > vcomp;
  std::vector<float> vf;
  apply(vcomp, vf, &std::abs<float>);
}

Живой пример на Ideone.

Однако лучшей идеей было бы просто взять тип функции в качестве параметра шаблона:

template <class T, class F>
void apply(const std::vector<std::complex<T> >& in, std::vector<T>& out, F f)
{
    out.resize(in.size());
    for(size_t i = 0; i < in.size(); ++i)
      out[i] = f(in[i]);
}

Живой пример на Ideone.

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

// taking std::abs as an example. It's not actually templated *and* overloaded
typedef float (*func_ptr)(std::complex<float> const&);
apply(vcomp, vf, (func_ptr)&std::abs<float>);
0 голосов
/ 02 февраля 2012

Насколько я могу судить, вам даже не нужно изобретать apply, поскольку то, что вы хотите, можно сделать с помощью std::transform:

#include <vector>
#include <complex>
#include <algorithm>

int main(){
  std::vector<std::complex<double> > complex_vec(10);
  std::vector<double> double_vec;
  double_vec.resize(complex_vec.size());
  std::transform(complex_vec.begin(), complex_vec.end(),
                 double_vec.begin(), std::abs<double>);
  return 0;
}
...