/************************************************************************/
/* */
/* Copyright 1998-2002 by Ullrich Koethe */
/* Cognitive Systems Group, University of Hamburg, Germany */
/* */
/* This file is part of the VIGRA computer vision library. */
/* The VIGRA Website is */
/* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */
/* Please direct questions, bug reports, and contributions to */
/* koethe@informatik.uni-hamburg.de or */
/* vigra@kogs1.informatik.uni-hamburg.de */
/* */
/* Permission is hereby granted, free of charge, to any person */
/* obtaining a copy of this software and associated documentation */
/* files (the "Software"), to deal in the Software without */
/* restriction, including without limitation the rights to use, */
/* copy, modify, merge, publish, distribute, sublicense, and/or */
/* sell copies of the Software, and to permit persons to whom the */
/* Software is furnished to do so, subject to the following */
/* conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the */
/* Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
/* OTHER DEALINGS IN THE SOFTWARE. */
/* */
/************************************************************************/
#ifndef VIGRA_FUNCTOREXPRESSION_HXX
#define VIGRA_FUNCTOREXPRESSION_HXX
/** \page FunctorExpressions Functor Expressions
Simple automatic functor creation by means of expression templates
(also known as a "lambda library").
\#include "vigra/functorexpression.hxx"
Namespace: vigra::functor
Note: This functionality is not available under Microsoft Visual C++,
because support for partial template specialization is required.
Motivation
Many generic algorithms are made more flexible by means of functors
which define part of the algorithms' behavior according to the
needs of a specific situation. For example, we can apply an exponential
to each pixel by passing a pointer to the exp function
to transformImage():
\code
vigra::FImage src(w,h), dest(w,h);
... // fill src
vigra::transformImage(srcImageRange(src), destImage(dest), &exp);
\endcode
However, this only works for simple operations. If we wanted to
apply the exponential to a scaled pixel value (i.e. we want to execute
exp(-beta*v)), we first need to implement a new functor:
\code
struct Exponential
{
Exponential(double b)
: beta(b)
{}
template
PixelType operator()(PixelType const& v) const
{
return exp(-beta*v);
}
double beta;
};
\endcode
This functor would be used like this:
\code
double beta = ...;
vigra::transformImage(srcImageRange(src), destImage(dest),
Exponential(beta));
\endcode
However, this approach has some disadvantages:
- Writing a functor is more work then simply programm the loop
directly, i.e. non-generically. Programmers will tend to
avoid generic constructs, if they require so much writing.
- Often, functors are only needed for a single expression.
It is not desirable to get into the trouble of introducing
and documenting a new class if that class is used only once.
- Functors cannot be implemented directly at the point of use.
Thus, to find out exactly what a functor is doing, one needs
to look somewhere else. This complicates use and maintainance
ot generic code.
Therefore, it is necessary to provide a means to generate functors on
the fly where they are needed. The C++ standard library contains so called
"functor combinators" that allow to construct complicated functors from
simpler ones. The above problem "apply exp(-beta*v) to every pixel"
would be solved like this:
\code
float beta = ...;
vigra::transformImage(srcImageRange(src), destImage(dest),
std::compose1(std::ptr_fun(exp),
std::bind1st(std::multiplies(), -beta)));
\endcode
I won't go into details on how this works. Suffice it to say that
this technique requires a functional programming style that is unfamiliar
to many programmers, and thus leads to code that is difficult to
understand. Moreover, this technique has some limitations that prevent
certain expressions from being implementable this way. Therefore, VIGRA
provides a better and simpler means to create functors on the fly.
Automatic Functor Creation
Automatic functor creation in VIGRA is based on a technique called
Expression Templates.
This means that C++ operators are
overloaded so that they don't execute the specified operation directly,
but instead produce a functor which will later calculate the result.
This technique has the big advantage that the familiar operator notation
can be used, while all the flexibility of generic programming is preserved.
Unfortunately, it requires partial template specialization, so these capabilities
are not available on compilers that dont support this C++ feature
(in particular, on Microsoft Visual C++).
The above problem "apply exp(-beta*v) to every pixel" will be solved
like this:
\code
using namespace vigra::functor;
float beta = ...;
transformImage(srcImageRange(src), destImage(dest),
exp(Param(-beta)*Arg1()));
\endcode
Here, four expression templates have been used to create the desired
functor:
- Param(-beta):
- creates a functor that represents a
constant (-beta in this case)
- Arg1():
- represents the first argument of the expression (i.e.
the pixels of image src in the example). Likewise, Arg2() and
Arg3() are defined to represent more arguments. These are needed
for algorithms that have multiple input images, such as
\ref combineTwoImages() and \ref combineThreeImages().
- * (multiplication):
- creates a functor that returns the product of
its arguments. Likewise, the other C++ operators (i.e.
+, -, *, /, %, ==, !=, <, <=, >, >=, &&, ||, &, |, ^, !, ~)
are overloaded.
- exp():
- creates a functor that takes the exponential of its
argument. Likewise, the other algebraic functions
(i.e. sqrt, exp, log, log10, sin, asin, cos, acos, tan,
atan, abs, floor, ceil, pow, atan2, fmod, min, max)
are overloaded.
We will explain additional capabilities of the functor creation mechanism
by means of examples.
The same argument can be used several times in the expression.
For example, to calculate the gradient magnitude from the components
of the gradient vector, you may write:
\code
using namespace vigra::functor;
vigra::FImage gradient_x(w,h), gradient_y(w,h), magnitude(w,h);
... // calculate gradient_x and gradient_y
combineTwoImages(srcImageRange(gradient_x), srcImage(gradient_y),
destImage(magnitude),
sqrt(Arg1()*Arg1() + Arg2()*Arg2()));
\endcode
It is also possible to build other functions into functor expressions. Suppose
you want to apply my_complicated_function() to the sum of two images:
\code
using namespace vigra::functor;
vigra::FImage src1(w,h), src2(w,h), dest(w,h);
double my_complicated_function(double);
combineTwoImages(srcImageRange(src1), srcImage(src2), destImage(dest),
applyFct(&my_complicated_function, Arg1()+Arg2()));
\endcode
[Note that the arguments of the wrapped function are passed as additional
arguments to applyFct()]
You can implement conditional expression by means of the ifThenElse()
functor. It corresponds to the "? :" operator that cannot be overloaded.
ifThenElse() can be used, for example, to threshold an image:
\code
using namespace vigra::functor;
vigra::FImage src(w,h), thresholded(w,h);
...// fill src
float threshold = ...;
transformImage(srcImageRange(src), destImage(thresholded),
ifThenElse(Arg1() < Param(threshold),
Param(0.0), // yes branch
Param(1.0)) // no branch
);
\endcode
You can use the Var() functor to assign values to a variable
(=, +=, -=, *=, /= are suported). For example, the average gray
value of the image is calculated like this:
\code
using namespace vigra::functor;
vigra::FImage src(w,h);
...// fill src
double sum = 0.0;
inspectImage(srcImageRange(src), Var(sum) += Arg1());
std::cout << "Average: " << (sum / (w*h)) << std::endl;
\endcode
For use in \ref inspectImage() and its relatives, there is a second
conditional functor ifThen() that emulates the if() statement
and does not return a value. Using ifThen(), we can calculate the size
of an image region:
\code
using namespace vigra::functor;
vigra::IImage label_image(w,h);
...// mark regions by labels in label_image
int region_label = ...; // the region we want to inspect
int size = 0;
inspectImage(srcImageRange(label_image),
ifThen(Arg1() == Param(region_label),
Var(size) += Param(1)));
std::cout << "Size of region " << region_label << ": " << size << std::endl;
\endcode
Often, we want to execute several commands in one functor. This can be done
by means of the overloaded operator,() ("operator comma"). Expressions
seperated by a comma will be executed in succession. We can thus
simultaneously find the size and the average gray value of a region:
\code
using namespace vigra::functor;
vigra::FImage src(w,h);
vigra::IImage label_image(w,h);
...// segment src and mark regions in label_image
int region_label = ...; // the region we want to inspect
int size = 0;
double sum = 0.0;
inspectTwoImages(srcImageRange(src), srcImage(label_image),
ifThen(Arg2() == Param(region_label),
(
Var(size) += Param(1), // the comma operator is invoked
Var(sum) += Arg1()
)));
std::cout << "Region " << region_label << ": size = " << size <<
", average = " << sum / size << std::endl;
\endcode
[Note that the list of comma-separated expressions must be enclosed in parentheses.]
A comma separated list of expressions can also be applied in the context of
\ref transformImage() and its cousins. Here, a general rule of C++ applies: The
return value of a comma expression is the value of its last subexpression.
For example, we can initialize an image so that each pixel contains its
address in scan order:
\code
using namespace vigra::functor;
vigra::IImage img(w,h);
int count = -1;
initImageWithFunctor(destImageRange(img),
(
Var(count) += Param(1),
Var(count) // this is the result of the comma expression
));
\endcode
Further information about how this mechanism works can be found in
this paper (sorry, slightly out of date).
*/
#ifndef DOXYGEN
#if !defined(NO_PARTIAL_TEMPLATE_SPECIALIZATION)
#include
#include
#include
namespace vigra {
namespace functor {
/************************************************************/
/* */
/* unary functor base template */
/* */
/************************************************************/
struct ErrorType;
template
struct ResultTraits0;
template
struct ResultTraits1
{
typedef T1 Res;
};
template
struct ResultTraits2
{
typedef typename PromoteTraits::Promote Res;
};
template
struct ResultTraits3
{
typedef typename PromoteTraits::Promote P1;
typedef typename PromoteTraits::Promote Res;
};
template
struct UnaryFunctor
{
UnaryFunctor(EXPR const & e)
: expr_(e)
{}
// typename ResultTraits0::Res
typename ResultTraits0::Res
operator()() const
{
return expr_();
}
template
typename ResultTraits1::Res
operator()(T1 const & v) const
{
return expr_(v);
}
template
typename ResultTraits2::Res
operator()(T1 const & v1, T2 const & v2) const
{
return expr_(v1, v2);
}
template
typename ResultTraits3::Res
operator()(T1 const & v1, T2 const & v2, T3 const & v3) const
{
return expr_(v1, v2, v3);
}
protected:
EXPR expr_;
};
template
struct ResultTraits0 >
{
typedef typename ResultTraits0::Res Res;
};
template
struct ResultTraits1, T1>
{
typedef typename ResultTraits1::Res Res;
};
template
struct ResultTraits2, T1, T2>
{
typedef typename ResultTraits2::Res Res;
};
template
struct ResultTraits3, T1, T2, T3>
{
typedef typename ResultTraits3::Res Res;
};
/************************************************************/
/* */
/* unary functors for arguments */
/* */
/************************************************************/
struct ArgumentFunctor1;
struct ArgumentFunctor2;
struct ArgumentFunctor3;
template <>
struct UnaryFunctor
{
UnaryFunctor()
{}
template
T1 const & operator()(T1 const & v1) const
{
return v1;
}
template
T1 const & operator()(T1 const & v1, T2 const &) const
{
return v1;
}
template
T1 const & operator()(T1 const & v1, T2 const &, T3 const &) const
{
return v1;
}
};
template <>
struct ResultTraits0 >
{
typedef ErrorType Res;
};
template
struct ResultTraits1, T1>
{
typedef T1 Res;
};
template
struct ResultTraits2, T1, T2>
{
typedef T1 Res;
};
template
struct ResultTraits3, T1, T2, T3>
{
typedef T1 Res;
};
/************************************************************/
inline
UnaryFunctor
Arg1()
{
return UnaryFunctor();
}
/************************************************************/
template <>
struct UnaryFunctor
{
UnaryFunctor()
{}
template
T2 const & operator()(T1 const &, T2 const & v2) const
{
return v2;
}
template
T2 const & operator()(T1 const &, T2 const & v2, T3 const &) const
{
return v2;
}
};
template <>
struct ResultTraits0 >
{
typedef ErrorType Res;
};
template
struct ResultTraits1, T1>
{
typedef ErrorType Res;
};
template
struct ResultTraits2, T1, T2>
{
typedef T2 Res;
};
template
struct ResultTraits3, T1, T2, T3>
{
typedef T2 Res;
};
/************************************************************/
inline
UnaryFunctor
Arg2()
{
return UnaryFunctor();
}
/************************************************************/
template <>
struct UnaryFunctor
{
UnaryFunctor()
{}
template
T3 const & operator()(T1 const &, T2 const &, T3 const & v3) const
{
return v3;
}
};
template <>
struct ResultTraits0 >
{
typedef ErrorType Res;
};
template
struct ResultTraits1, T1>
{
typedef ErrorType Res;
};
template
struct ResultTraits2, T1, T2>
{
typedef ErrorType Res;
};
template
struct ResultTraits3, T1, T2, T3>
{
typedef T3 Res;
};
/************************************************************/
inline
UnaryFunctor
Arg3()
{
return UnaryFunctor();
}
/************************************************************/
/* */
/* constant parameters */
/* */
/************************************************************/
template
struct ParameterFunctor
{
ParameterFunctor(T v)
: value_(v)
{}
T const & operator()() const
{
return value_;
}
template
T const & operator()(U1 const &) const
{
return value_;
}
template
T const & operator()(U1 const &, U2 const &) const
{
return value_;
}
template
T const & operator()(U1 const &, U2 const &, U3 const &) const
{
return value_;
}
protected:
T value_;
};
template
struct ResultTraits0 >
{
typedef T Res;
};
template
struct ResultTraits1, T1>
{
typedef T Res;
};
template
struct ResultTraits2, T1, T2>
{
typedef T Res;
};
template
struct ResultTraits3, T1, T2, T3>
{
typedef T Res;
};
template
UnaryFunctor >
Param(T const & v)
{
ParameterFunctor fv(v);
return UnaryFunctor >(fv);
}
/************************************************************/
/* */
/* unary analyser base template */
/* */
/************************************************************/
template
class UnaryAnalyser
{
public:
UnaryAnalyser(EXPR const & e)
: expr_(e)
{}
void operator()() const
{
expr_();
}
template
void operator()(T1 const & v) const
{
expr_(v);
}
template
void operator()(T1 const & v1, T2 const & v2) const
{
expr_(v1, v2);
}
template
void operator()(T1 const & v1, T2 const & v2, T3 const & v3) const
{
expr_(v1, v2, v3);
}
protected:
EXPR expr_;
};
/************************************************************/
/* */
/* variable assignment */
/* */
/************************************************************/
template
struct VarFunctor;
template
struct UnaryFunctor >;
/************************************************************/
#define MAKE_ASSIGNMENT_FUNCTOR(name, op) \
template \
struct AssignmentFunctor_##name \
{ \
AssignmentFunctor_##name(UnaryFunctor > v, \
UnaryFunctor const & e) \
: value_(v.value_), expr_(e) \
{} \
\
V & operator()() const \
{ \
const_cast(value_) op expr_(); \
return const_cast(value_); \
} \
\
template \
V & operator()(T1 const & v1) const \
{ \
const_cast(value_) op expr_(v1); \
return const_cast(value_); \
} \
\
template \
V & operator()(T1 const & v1, T2 const & v2) const \
{ \
const_cast(value_) op expr_(v1, v2); \
return const_cast(value_); \
} \
\
template \
V & operator()(T1 const & v1, T2 const & v2, T3 const & v3) const \
{ \
const_cast(value_) op expr_(v1, v2, v3); \
return const_cast(value_); \
} \
\
private: \
V & value_; \
UnaryFunctor expr_; \
};
/************************************************************/
MAKE_ASSIGNMENT_FUNCTOR(assign, =)
MAKE_ASSIGNMENT_FUNCTOR(add, +=)
MAKE_ASSIGNMENT_FUNCTOR(subtract, -=)
MAKE_ASSIGNMENT_FUNCTOR(multiply, *=)
MAKE_ASSIGNMENT_FUNCTOR(divide, /=)
#undef MAKE_ASSIGNMENT_FUNCTOR
/************************************************************/
/* */
/* variables */
/* */
/************************************************************/
template
struct UnaryFunctor >
{
typedef T Res;
UnaryFunctor(T & v)
: value_(v)
{}
template
UnaryAnalyser< AssignmentFunctor_assign > >
operator=(UnaryFunctor const & e)
{
AssignmentFunctor_assign > va(*this, e);
return UnaryAnalyser< AssignmentFunctor_assign > >(va);
}
template
UnaryAnalyser< AssignmentFunctor_add > >
operator+=(UnaryFunctor const & e)
{
AssignmentFunctor_add > va(*this, e);
return UnaryAnalyser< AssignmentFunctor_add > >(va);
}
template
UnaryAnalyser< AssignmentFunctor_subtract > >
operator-=(UnaryFunctor const & e)
{
AssignmentFunctor_subtract > va(*this, e);
return UnaryAnalyser< AssignmentFunctor_subtract > >(va);
}
template
UnaryAnalyser< AssignmentFunctor_multiply > >
operator*=(UnaryFunctor const & e)
{
AssignmentFunctor_multiply > va(*this, e);
return UnaryAnalyser< AssignmentFunctor_multiply > >(va);
}
template
UnaryAnalyser< AssignmentFunctor_divide > >
operator/=(UnaryFunctor const & e)
{
AssignmentFunctor_divide > va(*this, e);
return UnaryAnalyser< AssignmentFunctor_divide > >(va);
}
T const & operator()() const
{
return value_;
}
template
T const & operator()(U1 const &) const
{
return value_;
}
template
T const & operator()(U1 const &, U2 const &) const
{
return value_;
}
template
T const & operator()(U1 const &, U2 const &, U3 const &) const
{
return value_;
}
T & value_;
};
template
struct ResultTraits0 > >
{
typedef T Res;
};
template
struct ResultTraits1 >, T1>
{
typedef T Res;
};
template
struct ResultTraits2 >, T1, T2>
{
typedef T Res;
};
template
struct ResultTraits3 >, T1, T2, T3>
{
typedef T Res;
};
template
UnaryFunctor >
Var(T & v)
{
return UnaryFunctor >(v);
}
/************************************************************/
/* */
/* if then */
/* */
/************************************************************/
template
struct IfThenFunctor
{
typedef void Res;
IfThenFunctor(EXPR1 const & e1, EXPR2 const & e2)
: expr1_(e1), expr2_(e2)
{}
void operator()() const
{
if( expr1_() ) expr2_();
}
template
void operator()(T const & v1) const
{
if( expr1_(v1) ) expr2_(v1);
}
template
void operator()(T1 const & v1, T2 const & v2) const
{
if( expr1_(v1, v2) ) expr2_(v1, v2);
}
template
void operator()(T1 const & v1, T2 const & v2, T3 const & v3) const
{
if( expr1_(v1, v2, v3) ) expr2_(v1, v2, v3);
}
private:
EXPR1 expr1_;
EXPR2 expr2_;
};
template
UnaryAnalyser,
UnaryAnalyser > >
ifThen(UnaryFunctor const & e1,
UnaryAnalyser const & e2)
{
IfThenFunctor,
UnaryAnalyser > p(e1, e2);
return UnaryAnalyser,
UnaryAnalyser > >(p);
}
/************************************************************/
/* */
/* if then else */
/* */
/************************************************************/
template
struct IfThenElseFunctor;
template
struct ResultTraits0 >
{
typedef typename ResultTraits0::Res R2;
typedef typename ResultTraits0::Res R3;
typedef typename PromoteTraits::Promote Res;
};
template
struct ResultTraits1, T1>
{
typedef typename ResultTraits1::Res R2;
typedef typename ResultTraits1::Res R3;
typedef typename PromoteTraits::Promote Res;
};
template
struct ResultTraits2, T1, T2>
{
typedef typename ResultTraits2::Res R2;
typedef typename ResultTraits2::Res R3;
typedef typename PromoteTraits::Promote Res;
};
template
struct ResultTraits3, T1, T2, T3>
{
typedef typename ResultTraits3::Res R2;
typedef typename ResultTraits3::Res R3;
typedef typename PromoteTraits::Promote Res;
};
template
struct IfThenElseFunctor
{
IfThenElseFunctor(EXPR1 const & e1, EXPR2 const & e2, EXPR3 const & e3)
: expr1_(e1), expr2_(e2), expr3_(e3)
{}
typename ResultTraits0::Res
operator()() const
{
typename
ResultTraits0::Res
r2(expr2_());
typename
ResultTraits0::Res
r3(expr3_());
return expr1_() ? r2 : r3;
}
template
typename ResultTraits1::Res
operator()(T const & v1) const
{
typename
ResultTraits1::Res
r2(expr2_(v1));
typename
ResultTraits1::Res
r3(expr3_(v1));
return expr1_(v1) ? r2 : r3;
}
template
typename ResultTraits2::Res
operator()(T1 const & v1, T2 const & v2) const
{
typename
ResultTraits2::Res
r2(expr2_(v1, v2));
typename
ResultTraits2::Res
r3(expr3_(v1, v2));
return expr1_(v1, v2) ? r2 : r3;
}
template
typename ResultTraits3::Res
operator()(T1 const & v1, T2 const & v2, T3 const & v3) const
{
typename
ResultTraits3::Res
r2(expr2_(v1, v2, v3));
typename
ResultTraits3::Res
r3(expr3_(v1, v2, v3));
return expr1_(v1, v2, v3) ? r2 : r3;
}
private:
EXPR1 expr1_;
EXPR2 expr2_;
EXPR3 expr3_;
};
template
UnaryFunctor,
UnaryFunctor,
UnaryFunctor > >
ifThenElse(UnaryFunctor const & e1,
UnaryFunctor const & e2,
UnaryFunctor const & e3)
{
IfThenElseFunctor,
UnaryFunctor,
UnaryFunctor > p(e1, e2, e3);
return UnaryFunctor,
UnaryFunctor,
UnaryFunctor > >(p);
}
/************************************************************/
/* */
/* functors for unary functions */
/* */
/************************************************************/
#define MAKE_FUNCTOR_UNARY_FUNCTION(function) \
using std::function; \
template \
struct Functor_##function; \
\
template \
struct ResultTraits0 > \
{ \
typedef typename ResultTraits0::Res R1; \
typedef typename NumericTraits::RealPromote Res; \
}; \
\
template \
struct ResultTraits1, T1> \
{ \
typedef typename ResultTraits1::Res R1; \
typedef typename NumericTraits::RealPromote Res; \
}; \
\
template \
struct ResultTraits2, T1, T2> \
{ \
typedef typename ResultTraits2::Res R1; \
typedef typename NumericTraits::RealPromote Res; \
}; \
\
template \
struct ResultTraits3, T1, T2, T3> \
{ \
typedef typename ResultTraits3::Res R1; \
typedef typename NumericTraits::RealPromote Res; \
}; \
\
template \
struct Functor_##function \
{ \
Functor_##function(EXPR const & e) \
: expr_(e) \
{} \
\
typename ResultTraits0::Res \
operator()() const \
{ \
return function(expr_()); \
} \
\
template \
typename ResultTraits1::Res \
operator()(T const & v1) const \
{ \
return function(expr_(v1)); \
} \
\
template \
typename ResultTraits2::Res \
operator()(T1 const & v1, T2 const & v2) const \
{ \
return function(expr_(v1, v2)); \
} \
\
template \
typename ResultTraits3::Res \
operator()(T1 const & v1, T2 const & v2, T3 const & v3) const \
{ \
return function(expr_(v1, v2, v3)); \
} \
\
protected: \
\
EXPR expr_; \
}; \
\
template \
UnaryFunctor > > \
function(UnaryFunctor const & e) \
{ \
Functor_##function > p(e); \
return UnaryFunctor > >(p); \
}
/************************************************************/
MAKE_FUNCTOR_UNARY_FUNCTION(sqrt)
MAKE_FUNCTOR_UNARY_FUNCTION(exp)
MAKE_FUNCTOR_UNARY_FUNCTION(log)
MAKE_FUNCTOR_UNARY_FUNCTION(log10)
MAKE_FUNCTOR_UNARY_FUNCTION(sin)
MAKE_FUNCTOR_UNARY_FUNCTION(asin)
MAKE_FUNCTOR_UNARY_FUNCTION(cos)
MAKE_FUNCTOR_UNARY_FUNCTION(acos)
MAKE_FUNCTOR_UNARY_FUNCTION(tan)
MAKE_FUNCTOR_UNARY_FUNCTION(atan)
MAKE_FUNCTOR_UNARY_FUNCTION(abs)
MAKE_FUNCTOR_UNARY_FUNCTION(floor)
MAKE_FUNCTOR_UNARY_FUNCTION(ceil)
#undef MAKE_FUNCTOR_UNARY_FUNCTION
/************************************************************/
/* */
/* functors for unary operators */
/* */
/************************************************************/
#define MAKE_FUNCTOR_UNARY_OPERATOR(name, op) \
template \
struct Functor_##name; \
\
template \
struct ResultTraits0 > \
{ \
typedef typename ResultTraits0::Res Res; \
}; \
\
template \
struct ResultTraits1, T1> \
{ \
typedef typename ResultTraits1::Res Res; \
}; \
\
template \
struct ResultTraits2, T1, T2> \
{ \
typedef typename ResultTraits2::Res Res; \
}; \
\
template \
struct ResultTraits3, T1, T2, T3> \
{ \
typedef typename ResultTraits3::Res Res; \
}; \
\
template