2012-04-18 2 views
2

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

Мой шаблон выражение базисный вектор реализуется как этот

template <typename E> 
class VectorExpr { 
public: 
    int size() const { return static_cast<E const&>(*this).size(); } 

    float operator[](int i) const { return static_cast<E const&>(*this)[i]; } 

    operator E&() { return static_cast<E&>(*this); } 

    operator E const&() const { return static_cast<const E&>(*this); } 
}; // class VectorExpr 

Затем объект должен быть вектор будет выглядеть следующим образом

class Vector2 : public VectorExpr<Vector2> { 
public: 
    inline size_t size() const { return 2; } 

    template <typename E> 
    inline Vector2(VectorExpr<E> const& inExpr) { 
    E const& u = inExpr; 
    for(int i = 0; i < size(); ++i) 
     mTuple[i] = u[i]; 
    } 

private: 
    float mTuple[2]; 
}; 

Скажем, я хочу, чтобы применить зЬй :: грех ко всем элементам выражения

template <typename E> 
class VectorSin : public VectorExpr<VectorSin<E> > { 
    E const& mV; 

public: 
    VectorSin(VectorExpr<E> const& inV) : mV(inV) {} 

    int size() const { return mV.size(); } 

    float operator [] (int i) const { return std::sin(mV[i]); } 
}; 

Вопрос => Если я хочу добавить дополнительные функции, я copy-paste, что я делаю для функции sin, для каждой отдельной функции (например, cos, sqrt, fabs и т. д.). Как я могу избежать подобного копирования? Я пробовал вещи и понял, что я все еще низко в шаблоне-фу. Нет импульс не позволил ^^

+1

Так как вы учитесь, вы должны попробовать 11 C++ в лямбды вместе с станд :: for_each() ([примеры] (http://en.wikipedia.org/wiki/Anonymous_function#C.2B.2B)) – CAFxX

+0

Спасибо за предложение, я буду! На самом деле, я мог бы обойтись без C++ 11. Я часто запускаю числовой код в кластерах, где компиляторы не являются точно кровоточащими. – Monkey

ответ

4
template <typename F, typename E> 
class VectorFunc : public VectorExpr<VectorFunc<F, E> > { 
    E const& mV; 

public: 
    VectorSin(VectorExpr<E> const& inV) : mV(inV) {} 

    int size() const { return mV.size(); } 

    float operator [] (int i) const { return f(mV[i]); } 

    // this assumes the Functor f is default constructible, this is 
    // already not true for &std::sin. Adding the constructor that 
    // takes f, is left as an exercise ;) 
    F f; 
}; 
+0

Я пробовал что-то близко к этому. Это не удалось из-за этой проблемы std :: sin, которую вы упомянули. Поэтому мой вопрос заключается в том, как просто сделать это с помощью функции std :: sin. Сообщения об ошибках GCC здесь не очень полезны ... – Monkey

+0

@Monkey Я пропустил эту часть, потому что не знаю, как вы хотите добавить ее в свою грандиозную схему: вам нужно добавить конструктор, который принимает функтор 'F' и инициализирует член (возможно, предоставит ему аргумент по умолчанию, поэтому он по-прежнему работает без проблем с функционалами DefaultConstructible). – pmr

2

В дополнение к ответу по pmr, стандартные <cmath> функции не являются функторы, так что вы не можете использовать их непосредственно указать уникальные специализации вашего класса - то есть вы бы не есть отдельный экземпляр шаблона для std :: sin по сравнению с std :: cos (что я собираю, к чему вы стремитесь, исправьте меня, если я неправильно вас понял).

Вы можете создать оболочку, чтобы сопоставить указатель на определенный тип, например.

#include <iostream> 

template< void (*FuncPtr)() > struct Func2Type 
{ 
    void operator()() { FuncPtr(); } 
}; 

void Hello() { std::cout << "Hello" << std::endl; } 
void World() { std::cout << "world" << std::endl; } 

int main() 
{ 
    Func2Type<Hello> test1; 
    Func2Type<World> test2; 
    test1(); 
    test2(); 
} 

Таким образом, вы могли бы использовать их в качестве аргументов шаблона точно так же, как обычный класс функтора

+0

Также известен как устаревший 'std :: pointer_to_unary/binary_function' Мы должны позволить им покоиться. (Они, вероятно, уже отдыхают дольше, чем они устарели. Бесполезные ублюдки.;) – pmr

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