2009-02-26 3 views
0

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

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 приведенном выше примере вне; также, я должен написать новый для каждого числа аргументов, которые я хотел бы пройти (что кажется неизбежным).

Любые мысли о том, как достичь этого (с минимальным условным кодом)?

ответ

3

Вот почему типы unary_function, binary_function и т. Д. В его STL имеют typedefs 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; 
} 
+0

я (1) ошибка: ожидается, тип спецификатор (1) ошибка: ожидается, '>' (2) Ошибка: аргументы шаблона по умолчанию не могут быть использованы в шаблонах функций (Я пронумеровал строки, основанные на вашем примере.) Я использую gcc v4.2.4. –

1

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

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; 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^