Как легко применить функцию к коллекции в C ++ - PullRequest
0 голосов
/ 26 февраля 2009

Я храню изображения в виде массивов, настроенных на основе типа их элементов, таких как Image<unsigned> или Image<float> и т. Д. Часто мне нужно выполнять операции с этими изображениями; например, мне может понадобиться добавить два изображения или квадратное изображение (поэлементно) и так далее. Все операции являются поэлементными. Я хотел бы максимально приблизиться к написанию таких вещей, как:

float Add(float a, float b) { return a+b; }
Image<float> result = Add(img1, img2);

и даже лучше, такие вещи, как

complex ComplexCombine(float a, float b) { return complex(a, b); }
Image<complex> result = ComplexCombine(img1, img2);

или

struct FindMax {
    unsigned currentMax;
    FindMax(): currentMax(0) {}
    void operator(unsigned a) { if(a > currentMax) currentMax = a; }
};

FindMax findMax;
findMax(img);
findMax.currentMax;  // now contains the maximum value of 'img'

Теперь я явно не могу этого сделать; Я написал что-то, чтобы я мог позвонить:

Image<float> result = Apply(img1, img2, Add);

но я не могу найти общий способ определения типа возвращаемого объекта функции / функции, поэтому мой приведенный выше пример ComplexCombine отсутствует; Кроме того, я должен написать новый для каждого числа аргументов, которые я хотел бы передать (что кажется неизбежным).

Есть мысли о том, как этого добиться (используя как можно меньше стандартного кода)?

Ответы [ 2 ]

3 голосов
/ 26 февраля 2009

Вот почему типы unary_function, binary_function и т. Д. В STL имеют значения типа result_type. Если вы используете std :: ptr_fun, вы можете воспользоваться этим с помощью Apply,

, например

template<typename Func, typename Arg, typename Result = Func::result_type>
Image<Result> Apply(Arg a1, Arg a2, Func f) {
        return Image<Result>(f(a1,a2));
}

И делай,

Apply(img1, img2, std::ptr_fun(&Add));

Хорошо, вы меня поймали, я не проверял. Это все еще возможно, но больше работы без возможности непосредственного использования некоторых функций STL

#include <iostream>

template<typename T>
struct Image {
  T val_;
  Image(const T& val) : val_(val) {}
};

template<typename Arg1, typename Arg2, typename Result>
struct image_fun_adapter {
  Result (*f)(Arg1, Arg2);
  Image<Result> operator()(const Image<Arg1>& a1, const Image<Arg2>& a2) {
    return Image<Result>(f(a1.val_, a2.val_));
  }
};

template<typename Arg1, typename Arg2, typename Result>
image_fun_adapter<Arg1,Arg2,Result> image_fun_ptr(Result (*f)(Arg1,Arg2)) {
  image_fun_adapter<Arg1,Arg2,Result> rv;
  rv.f = f;
  return rv;
}

float Add(float a, float b) { return a + b; }

int main() {
  Image<float> a(1.0);
  Image<float> b(12.5);
  // this is the cute bit:
  Image<float> c = image_fun_ptr(&Add)(a,b);

  std::cout << c.val_ << std::endl;
  return 0;
}
1 голос
/ 26 февраля 2009

Шаблон специализации!

template<typename T>
T Add(const T &left, const T &right)
{
    return left + right;
}

template<typename T>
struct AddTwo
{
    T operator()(const T &left, const T &right)
    {
        return Add(left, right);
    }
};

// something like this (not exactly sure)
template<std::vector<typename V>>
std::vector<V> Add(const std::vector<V> &left, const std::vector<V> &right)
{
    assert(left.size() == right.size());

    std::vector ret(left.size());

    std::transform(left.const_begin(), left.const_end(), right.const_begin(), ret.begin(), AddTwo());

    return ret;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...