I have the following abstract base class:
class Function {
virtual double Eval(double x) const = 0;
};
I want to be able to use expressions like f * g or f->operator *(g), where f and g are concrete objects of the class Function, in my main file, say for example when I want to calculate a definite integral so that I can write:
AnIntegrationMethod(f*g);
A rather unsophisticated method I came up with consists of declaring a class Product (only header file shown, the implementation is obvious):
class Product: public Function {
public: Product(Function *g, Function *f);
~Product();
virtual double Eval(double x) const; //return _g->Eval(x)*_f->Eval(x)
private: Function *_g; Function *_f;
};
and then in any of my functions
#include "Product.h"
class ConcreteFunction: public Function {
public:
ConcreteFunction();
~ConcreteFunction();
virtual double Eval(double x) const;
Function* operator*(Function *f) {return new Product(this, f);}
};
This actually works for simple stuff but the problem is that the operator * is only defined within single derived classes of the base class instead of being defined for every possible derived class. This means, for instance, that if I have a concrete object f representing a mathematical function I can call f->operator *g but if I want to call again the operator * to get the object (f->operator * g)->operator * f I am not going to be able to because the function f* g does not have the * operator defined as f.
I suppose I should define the operator * directly in my base class but then I can't figure out how to implement the operator because I don't really know how to get the proper Eval function for the product since I cannot use the class Product now, it wouldn't make sense to use the class Product derived from the class Function in the class Function itself. I think I'm also quite confused over whether in general is correct to write something like the following:
Function* Function::operator*(Function *f) {
Function *g;
...
//operations that allow g to be have the right Eval function
//which should of the sort this->Eval(x) * f->Eval(x)
...
return g;
}
Any hints or suggestions on how to proceed are appreciated. My level is very basic, I've been programming two month now.
Just a sketch, you might do something like this:
#include <memory>
// Base Function: f(x) = x
class Function
{
protected:
struct Implementation
{
virtual ~Implementation() {}
virtual double evaluate(double x) const { return x; }
};
public:
Function()
: self(std::make_shared<Implementation>())
{}
double operator () (double x) const { return self->evaluate(x); }
protected:
Function(std::shared_ptr<Implementation> self)
: self(self)
{}
private:
std::shared_ptr<Implementation> self;
};
typedef Function Identity;
// Unary Function: u(-f(x))
class UnaryMinus : public Function
{
protected:
struct Implementation : Function::Implementation
{
Function f;
Implementation(Function f)
: f(f)
{};
virtual double evaluate(double x) const override { return -f(x); }
};
public:
UnaryMinus(Function f)
: Function(std::make_shared<Implementation>(f))
{}
};
// Binary Function: u(f(x) + g(x))
class BinaryAdd : public Function
{
protected:
struct Implementation : Function::Implementation
{
Function f;
Function g;
Implementation(Function f, Function g)
: f(f), g(g)
{};
virtual double evaluate(double x) const override { return f(x) + g(x); }
};
public:
BinaryAdd(Function f, Function g)
: Function(std::make_shared<Implementation>(f, g))
{}
};
// Binary Function: u(f(x) * g(x))
class BinaryMultiply : public Function
{
protected:
struct Implementation : Function::Implementation
{
Function f;
Function g;
Implementation(Function f, Function g)
: f(f), g(g)
{};
virtual double evaluate(double x) const override { return f(x) * g(x); }
};
public:
BinaryMultiply(Function f, Function g)
: Function(std::make_shared<Implementation>(f, g))
{}
};
inline UnaryMinus operator - (Function f) { return UnaryMinus(f); }
inline BinaryAdd operator + (Function f, Function g) { return BinaryAdd(f, g); }
inline BinaryMultiply operator * (Function f, Function g) { return BinaryMultiply(f, g); }
#include <iostream>
int main() {
Identity x;
Function result = -x * (x + x) + x;
std::cout << result(2) << '\n';
}
You could overload operator* as a free-standing function. Put it in Product.h/cpp even if it is not a member of Product, since it is tightly related to it.
In Product.h:
Function* operator*(Function *f, Function *g);
In Product.cpp:
Function* operator*(Function *f, Function *g) {
return new Product(f, g);
}
Same with addition, subtraction, etc.
Alternatively, you can implement them as member functions, but put the definition in Function.cpp and include Product.h, etc. there.
Note that your design has a huge flaw. You create new Function objects on the heap and pass around pointers. You need to delete them somewhere in your code, I assume in your deconstructors. But then you also need to take care about copying your objects. Usually, it is a nightmare to care about proper deletion manually, and there are automatic ways to do it (called "memory management"). You could consider using smart pointers, for example. Have a look at std::shared_ptr. While not being most efficient in every case, it is a good thing to use in general when you first want to learn the language and not too many details about memory management. To apply shared_ptr to your code, replace every Function* with shared_ptr<Function>, and replace new Function(...) with make_shared<Function>(...) (and the same with other types).
Also note that * for math functions is ambiguous: In some contexts / literature, f*g means multiplying the result, while in others it means function convolution.
Here's a C++11 generic programming solution that doesn't rely on inherited polymorphism (i.e. - virtual functions) and doesn't require dynamic allocation.
I'm not a C++ expert and this can likely be improved upon significantly, but it works and gets the idea across. In particular, the code below only works for functions of double's. You can probably make the operands and return types be a template type too, so that this can generically work on different types (e.g. - complex) too. I don't know the proper way to scope the template operators so that you can use the shorthand operator notation and not have them accidentally invoked on (or make ambiguous) other types that have operator()(double x). If anyone has any suggestions to improve upon this answer, then please chime in and I'll edit my answer.
#include <iostream>
using namespace std;
struct Identity
{
double operator() (double x) const { return x; }
};
struct Constant
{
template<typename T1>
Constant(const T1 &x) : _x(x) {}
double operator()(double x) const { return _x; }
private:
double _x;
};
template<typename T1>
struct Negate
{
Negate(const T1 &f) : _f(f) {}
double operator() (double x) const { return -_f(x); }
private:
T1 _f;
};
template<typename T1>
struct Reciprocal
{
Reciprocal(const T1 &f) : _f(f) {}
double operator() (double x) const { return 1 / _f(x); }
private:
T1 _f;
};
template<typename T1, typename T2>
struct Sum
{
Sum(const T1 &f, const T2 &g) : _f(f), _g(g) {}
double operator() (double x) const { return _f(x) + _g(x); }
private:
T1 _f;
T2 _g;
};
template<typename T1, typename T2>
struct Product
{
Product(const T1 &f, const T2 &g) : _f(f), _g(g) {}
double operator() (double x) const { return _f(x) * _g(x); }
private:
T1 _f;
T2 _g;
};
template<typename T1>
Negate<T1> operator-(const T1 &f)
{ return Negate<T1>(f); }
template<typename T1, typename T2>
Sum<T1, T2> operator+(const T1 &f, const T2 &g)
{ return Sum<T1, T2>(f, g); }
template<typename T1, typename T2>
Sum<T1, Negate<T2> > operator-(const T1 &f, const T2 &g)
{ return Sum<T1, Negate<T2> >(f, Negate<T2>(g)); }
template<typename T1, typename T2>
Product<T1, T2> operator*(const T1 &f, const T2 &g)
{ return Product<T1, T2>(f, g); }
template<typename T1, typename T2>
Product<T1, Reciprocal<T2> > operator/(const T1 &f, const T2 &g)
{ return Product<T1, Reciprocal<T2> >(f, Reciprocal<T2>(g)); }
int main()
{
auto f = (Identity() * Constant(4.0) + Constant(5)) / Identity(); // f(x) = (x * 4 + 5) / x; f(2) = 6.5
auto g = f * f; // g(x) = f(x) * f(x); g(2) = 42.25
cout << f(2) << " " << g(2) << " " << (g / f)(2) << endl; // prints 6.5 42.25 6.5
return 0;
}
EDIT: The main drawback of this approach is that the type of a "formula" must be fully known at compile time and embedded in the template generated classes. That means that very complicated formulas will generate lots of different classes and code. So, this approach could lead to nasty code bloat. Also, you can't do something like:
for (i = 1; i < j; ++i) // raise f to the jth power (other than 0)
f *= f;
Since the type of f must be fully known at compile time and the multiplication is invoking new types iteratively. The other approaches that use a class hierarchy, dynamic allocation (with auto-cleanup) and polymorphism can do this though and don't have the problem of code bloat. Still, it was interesting to try.
Related
I have a hash process implemented using Howard Hinnant's method (generic hash based on hash_append overloads).
The purpose of that method is to create hash of classes in order to "memoize" result of computations (see end of this answer), so I am facing some issue. In particular, consider the following possible Input class that needs to be hashed:
struct A {
virtual int do_stuff() const = 0;
virtual ~A();
};
struct B: A {
int do_stuff() const override { return 0; }
};
struct C: A {
const int u;
int do_stuff() const override { return u; }
};
struct Input {
A const& a; // store a reference to an instance of B or C
};
Now, if I want to hash Input, I will have something like:
template <class HashAlgorithm>
void hash_append(HashAlgorithm& h, Input const& input) {
hash_append(h, typeid(input));
hash_append(h, typeid(input.a));
}
So I need an overload of hash_append for A:
template <class HashAlgorithm>
void hash_append(HashAlgorithm& h, A const& a) {
hash_append(h, typeid(a));
}
The problem here is that depending on the runtime type of a, I would need to add extra information to the hash, e.g. for C I would need to add u.
I thought about the following solutions (and drawbacks):
add a virtual method to A that returns a specific value that can be added to the typeid() hash, but:
this means adding a method inside A that is not related to the purpose of A, thus I don't really like this idea (in particular because I have multiple A-like classes);
this breaks the concept of hash_append since the method will have a unique return type for all inheriting classes.
do a bunch of dynamic_cast inside hash_append:
I found this pretty ugly... in particular if I have multiple classes similar to A;
this is error-prone: if someone adds a new children of A and do not add a dynamic_cast inside hash_append.
Is there a way to hash a polymorphic type, without having to modify the type itself or rely on a bunch of dynamic_cast?
The final goal of this is to be able to memoize results of some heavy functions. Let's sketch the basic structure of my application:
struct Input { };
struct Result { };
Result solve(Input const&);
The solve function is computationally-heavy, so I want to save the results of previous computation in file using hash of Inputs, e.g. something like:
// depends on hash_append
std::string hash(Input const&);
Result load_or_solve(Input const& input) {
auto h = hash(input);
Result result;
if (exists(h)) { // if result exists, load it
result = load(h);
}
else { // otherwize, solve + store
result = solve(input);
store(h, result);
}
return result;
}
The load and store methods would load and store results from files, the goal is to memoize solutions between different runs.
If you have suggestion on how to memoize these results without having to deal with the above issues, I'll be glad to read them.
You can use double dispatching within the hash_append version of A and forward the request to the proper version (that is the one either for B or C). The drawback is that you must add boilerplate to those classes to accept a visitor and I cannot say if it's acceptable for you.
Here is a bunch of code that should illustrate the idea:
struct B;
struct C;
struct Visitor {
virtual void visit(const B &) = 0;
virtual void visit(const C &) = 0;
};
template<typename T, typename... O>
struct HashVisitor: T, HashVisitor<O...> {
template<typename U>
std::enable_if_t<std::is_same<T, U>::value> tryVisit(const U &u) {
T::operator()(u);
}
template<typename U>
std::enable_if_t<not std::is_same<T, U>::value> tryVisit(const U &u) {
HashVisitor<O...>::visit(u);
}
void visit(const B &b) override { tryVisit<B>(b); }
void visit(const C &c) override { tryVisit<C>(c); }
};
template<>
struct HashVisitor<>: Visitor {};
template<typename... F
auto factory(F&&... f) {
return HashVisitor<std::decay_t<F>>{std::forward<F>(f)...};
}
struct A {
virtual void accept(Visitor &) = 0;
virtual int do_stuff() const = 0;
virtual ~A();
};
struct B: A {
void accept(Visitor &v) override { v.visit(*this); }
int do_stuff() const override { return 0; }
};
struct C: A {
const int u;
void accept(Visitor &v) override { v.visit(*this); }
int do_stuff() const override { return u; }
};
template <class HashAlgorithm>
void hash_append(HashAlgorithm &, const B &) {
// do something
}
template <class HashAlgorithm>
void hash_append(HashAlgorithm &, const C &) {
// do something
}
template <class HashAlgorithm>
void hash_append(HashAlgorithm &h, const A &a) {
auto vis = factory(
[&h](const B &b){ hash_append(h, b); },
[&h](const C &c){ hash_append(h, c); }
);
a.accept(vis);
}
In C++, we can pass a function/functor to a function like so:
template <typename F>
void doOperation(int a, int b, F f){
std::cout << "Result: " << f(a,b) << std::endl;
}
we can then use both functions and functors:
int add(const int &a, const int &b){ return a+b; }
struct subtract(){
void operator() (const int &a, const int &b) { return a-b; }
};
and use it in the following manner:
doOperation(1,2,add);
doOperation(5,2,subtract());
My question is, can I do something similar with a class and pass a function as an argument to a class, store it and use it later? E.g.
template <typename F>
class doOperation{
public:
doOperation(int &a, int &b, F f) : a(a), b(b), f(f) {};
void setOperands(int &a, int &b) { this->a = a; this->b = b };
void performCalculation(){
std::cout << "Result: " << f(a,b) << std::endl;
}
private:
int a,b;
F f;
}
So that we may assign it a function once and then later use it:
doOperation summing(1,2,add);
summing.setOperands(2,3);
summing.performCalculation();
doOperation subtraction(7,3,subtract());
subtraction.performCalculation();
If my examples are valid, I would appreciate the explanation for the mechanics here as I seem to be getting a bit lost. In case I missed something, I am looking for hints on whether this can be achieved.
Lastly, how would I then use such a class doOperation in other functions and classes. For example, would defining something like this inside a member function require me to template the new class, its member function, and how would it be declared and used:
class higherFunctionality{
public:
higherFunctionality() {...}
void coolThings(){
doOperation *myOperation = operationFactory( ... );
myOperation->setOperands(4,5);
myOperation->performCalculation();
}
};
Yes, but you have to supply the type when you instantiate template classes. The usual way to deal with this is to create a helper function:
template < typename Fun > struct operation_class
{
operation_class(Fun f) : fun{f} {}
Fun fun;
};
template < typename Fun >
operation_class<Fun> operation(Fun fun) { return operation_class<Fun>{fun}; }
int main()
{
auto op0 = operation(some_fun);
auto op1 = operation(some_functor{});
}
Frankly though, you are better off just using lambda:
auto op0 = [a,b]() { return sum(a,b); };
auto op1 = [a,b]() { return subtract{a,b}(); }
// C++17:
auto op2 = [op=subtract{a,b}] { return op(); };
I have two classes in library:
class A
{
public:
int x;
};
template <class T>
class B : public A
{
public:
T y;
};
And have method:
... Method(A &a, A &b);
How compare y from a and b if a, b always have same type
B <T>
, but type of T unknown?
When you have a function,
Method(A a, A b);
You have lost the B part of the objects due to object slicing.
If you want retain the B part of the objects, you have to use references or pointers.
Method(A const& a, A const& b);
or
Method(A const* a, A const* b);
In order for Method to work correctly, you have to provide a way for the objects to be treated as B. You can use that using a virtual function in A.
class A
{
public:
int x;
virtual int compare(A const& rhs) const
{
return (this->x - rhs.x);
}
};
and make sure to override the function in B.
template <class T>
class B : public A
{
public:
T y;
virtual int compare(A const& rhs) const
{
// Use the base class first.
int r = A::compare(rhs);
// If the base class result is adequate, return.
if ( r != 0 )
{
return r;
}
// Do a dynamic_cast of the rhs.
B const* rhsPtr = dynamic_cast<B const*>(&rhs);
// If the dynamic_cast didn't succeed, need
// to figure out how to handle the case.
if ( rhsPtr == nullptr )
{
// Add error handling code
}
return (this->y - rhsPtr->y);
}
};
Then, in Method,
Method(A const& a, A const& b)
{
int r = a.compare(b);
}
A possible solution is to create a virtual function that will do the comparison.
Inside the body of the implementation in the derived class the type T is known and you'll have no problems.
struct Base {
...
virtual bool same_y(const Base& other) const = 0;
};
template<typename T>
struct Derived : Base {
T y;
virtual bool same_y(const Base& other) const {
return dynamic_cast< const Derived<T>& >(other).y == y;
}
};
You could define Method as a template method.
template<typename T>
bool Method(const A& a, const A& b)
{
const B<T>& first = dynamic_cast<const B<T>&>(a);
const B<T>& second = dynamic_cast<const B<T>&> (b);
return first.y == second.y;
}
With this approach you don't have to know the type of T inside Method. But you have to specify T when you call it:
bool areEqual = Method<int>(a, b);
Maybe that is no problem in your case.
Be aware that whenever you assign a B<T> to a variable of type A you are loosing the information that is specific to B<T> (in this case the value of y is lost). That's why I changed the signature of Method in order to take references instead of values.
This question already has answers here:
C++ Memoization understanding
(3 answers)
Writing Universal memoization function in C++11
(5 answers)
Closed 8 years ago.
Consider the following code (compiles with gcc 4.7.2):
#include<iostream>
#include<memory>
struct Base
{
~Base() {}
virtual double operator()(double x) const = 0;
};
template<typename F, typename G> struct Compose;
struct A : public Base
{
virtual double operator()(double x) const {return x;} //suppose this is a hard-to.calculate function, lots of temporaries, maybe also time-dependent, etc
template <typename F>
Compose<A,F> operator()(const F& f) const {return Compose<A,F>(*this,f);}
};
struct B : public Base
{
virtual double operator()(double x) const {return x*x;} //suppose this is a hard-to.calculate function, lots of temporaries, maybe also time-dependent, etc
template <typename F>
Compose<B,F> operator()(const F& f) const {return Compose<B,F>(*this,f);}
};
struct C : public Base
{
virtual double operator()(double x) const {return x*x*x;} //suppose this is a hard-to.calculate function, lots of temporaries, maybe also time-dependent, etc.
template <typename F>
Compose<C,F> operator()(const F& f) const {return Compose<C,F>(*this,f);}
};
template<typename F, typename G>
struct Compose : public Base
{
Compose(const F &_f, const G &_g) : f(_f), g(_g) {}
F f;
G g;
virtual double operator()(double x) const {return f(g(x));}
};
int main()
{
double x=2.0;
A a;
B b;
C c;
std::shared_ptr<Base> ptrBase = std::make_shared<A>(A());
std::shared_ptr<A> ptrA = std::make_shared<A>(a);
std::cout<< a(x) <<std::endl;
std::cout<< ptrBase->operator()(x) <<std::endl;
std::cout<< ptrA->operator()(x) <<std::endl;
std::cout<< b(a(x)) <<std::endl;
std::cout<< c(b(a(x))) <<std::endl;
std::cout<< a(c(b(a(x)))) <<std::endl;
std::cout<< ptrA->operator()(c(b(ptrBase->operator()(x)))) <<std::endl;
}
Output:
2
2
2
4
64
64
64
Ok, long prelude for a short question. Several redundant calculations occur here, for instance, the result of A()(x) is calculated six times (some via objects, some via pointers). How can I implement a global output array which stores the evaluated function values?
One approach which came to my mind and should work is to implement a function std::string id() unique to each (composed) class, plus a global std::map<std::string,double> to store the results, and then check whether a (current) result exists.
Do you see other and maybe better approaches here? Thanks in advance.
Sorry guys, although there are some similarities (the word "memoization" which seems to somehow trigger a reflex), I really don't see why this should be duplicate ... but I'm open to discussion.
The case above is in my opinion much more complex than those in the linked threads (e.g., its not simply a fibonacci-function). Moreover, as far I can see the highlighted memoization class will treat objects and pointers differently (at least without further editing). My intention was to arrive at a pattern in which each result is calculated only once, regardles how it is invoked.
Up to now, I was playing around with CRTP'ed static results classes, which leads to the following code (compiles with gcc 4.7.2.):
#include<iostream>
#include<memory>
#include<string>
#include<map>
struct Base
{
virtual ~Base() {}
virtual double operator()(double x) const = 0;
virtual std::string id() const = 0;
};
template<typename F, typename G> struct Compose;
template<typename T>
struct Result
{
virtual ~Result() {}
double get(double x) const
{
return mem.find(x)->second;
}
bool isSet(double x) const {it=mem.find(x); return it!=mem.end();}
//get the previously found result by isSet(x)
double get() const
{
return it->second;
}
protected:
//the set function is const, as it works only on static variables
//don't know whether it is the best idea, but it allows for a const operator() later...
void set(double x, double y) const
{
mem.insert(std::make_pair(x,y));
}
private:
static std::map<double, double> mem;
static std::map<double, double>::const_iterator it;
};
template<typename T> std::map<double, double> Result<T>::mem;
template<typename T> std::map<double, double>::const_iterator Result<T>::it=Result<T>::mem.begin();
struct A : public Base, public Result<A>
{
virtual double operator()(double x) const
{
if(isSet(x))
{
return get();
}
else
{
double y=x;
set(x,y);
std::cout<<"setA ";
return y;
}
}
template <typename F>
Compose<A,F> operator()(const F& f) const {return Compose<A,F>(*this,f);}
virtual std::string id() const {return "A";}
};
struct B : public Base, public Result<B>
{
virtual double operator()(double x) const
{
if(isSet(x))
{
return get();
}
else
{
double y=x*x;
set(x,y);
std::cout<<"setB ";
return y;
}
}
template <typename F>
Compose<B,F> operator()(const F& f) const {return Compose<B,F>(*this,f);}
virtual std::string id() const {return "B";}
};
struct C : public Base, public Result<C>
{
virtual double operator()(double x) const
{
if(isSet(x))
{
return get();
}
else
{
double y=x*x*x;
set(x,y);
std::cout<<"setC ";
return y;
}
}
template <typename F>
Compose<C,F> operator()(const F& f) const {return Compose<C,F>(*this,f);}
virtual std::string id() const {return "C";}
};
template<typename F, typename G>
struct Compose : public Base, public Result<Compose<F,G> >
{
Compose(const F &_f, const G &_g) : f(_f), g(_g) {}
F f;
G g;
virtual double operator()(double x) const
{
if(this->isSet(x))
{
return this->get();
}
else
{
double y=f(g(x));
this->set(x,y);
std::cout<<"set"<<this->id()<<" ";
return y;
}
}
virtual std::string id() const {return f.id() + "(" + g.id() + ")";}
};
int main()
{
double x=2.0;
A a;
B b;
C c;
std::shared_ptr<Base> ptrBase = std::make_shared<A>(A());
std::shared_ptr<A> ptrA = std::make_shared<A>(A());
std::cout<<"-------------------------------"<<std::endl;
std::cout<< a(x) <<std::endl;
std::cout<<ptrBase->operator()(x) <<std::endl;
std::cout<<ptrA->operator()(x) <<std::endl;
std::cout<<"-------------------------------"<<std::endl;
std::cout<<c(x)<<std::endl;
std::cout<<C()(x)<<std::endl;
std::cout<<C()(x)<<std::endl;
std::cout<<"-------------------------------"<<std::endl;
auto ba= b(a);
std::cout<<ba(x) << std::endl;
auto cba= c(ba);
std::cout<<cba(x)<< std::endl;
auto acba= a(cba);
std::cout<<acba(x)<<std::endl;
}
Output:
-------------------------------
setA 2
2
2
-------------------------------
setC 8
8
8
-------------------------------
setB setB(A) 4
setC(B(A)) 64
setA(C(B(A))) 64
-------------------------------
Ok, some things to note here:
By inheritance from the static results class, it is interesting how all the differently called A's (by object, by pointer-to-object, by pointer-to-base) retrieve the stored result (there is only one set). Same for C() which is called three times but set only once.
In order to anticipate the next reflex, I know that multiple inheritance can be bad, but the classes seem to be well separated. The same behavior is probably obtained by composition, so please forget about that point.
In fact, this isn't really a memoization class yet, as it simply stores the result which was calculated first. Thus it also gives wrong results [eg. for C(B(A))]. However, this can be easily cured by a map or whatever. I will do this later eventually, at the moment its only about the pattern (EDIT: is done).
And as a last point, I'm aware that a different solution than in the seemingly-duplicated threads doesn't imply a different questions. Yet, it will maybe (--hopefully) yield some extension of the memoization-topic on this page from which all can benefit.
I'm looking forward to your thoughts. Thanks in advance!
EDIT 2: Helping yourself is a good thing, now the code works as I was looking for. I have updated it in the post above.
Changes:
Added a map to actually make a real memoization class out of it. Caution: double comparison is dangerous, so one should better pass a more approriate comparison function instead of the standard equality.
Made the static members of the results array private, and the setters protected, as only the function-classes may change the results.
Still the map types are not given by template parameters (as in the linked threads). That is overhead which I don't need (and probably YAGNI too).
Now I'll stop talking to myself. Comments are still welcome. Thanks, David
As an exercise for my personal enlightenment, I implement vector math with expression templates. I want to implement some operations that apply the same unary function to all elements to a vector expression. So far, I do this.
My base vector expression template is implemented like this
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
Then, an object supposed to be a vector will look like this
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];
};
Let's say I want to apply std::sin to all elements of an expression
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]); }
};
Question => If I want to add more functions, I copy-paste what I do for the sin function, for every single function (like cos, sqrt, fabs, and so on). How I can avoid this kind of copy-pasting ? I tried things and figured out I'm still low in template-fu. No boost allowed ^^
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;
};
In addition to the answer by pmr, The standard <cmath> functions aren't functors, so you couldn't use them directly to specify unique specialisations of your class - i.e. you wouldn't have a separate template instantiation for std::sin versus std::cos (which is what I gather you're aiming for? correct me if I've misunderstood you on that).
You could create a wrapper in order to map a function pointer to a distinct type, e.g.
#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();
}
That way you could use them as template arguments in the same way as a normal functor class