/************************************************************************/ /* */ /* 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: 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 \ struct Functor_##name \ { \ Functor_##name(EXPR const & e) \ : expr_(e) \ {} \ \ typename ResultTraits0::Res \ operator()() const \ { \ return op expr_(); \ } \ \ template \ typename ResultTraits1::Res \ operator()(T const & v1) const \ { \ return op expr_(v1); \ } \ \ template \ typename ResultTraits2::Res \ operator()(T1 const & v1, T2 const & v2) const \ { \ return op expr_(v1, v2); \ } \ \ template \ typename ResultTraits3::Res \ operator()(T1 const & v1, T2 const & v2, T3 const & v3) const \ { \ return op expr_(v1, v2, v3); \ } \ protected: \ \ EXPR expr_; \ }; \ \ template \ UnaryFunctor > > \ operator op(UnaryFunctor const & e) \ { \ Functor_##name > p(e); \ return UnaryFunctor > >(p); \ } /************************************************************/ MAKE_FUNCTOR_UNARY_OPERATOR(minus, -) MAKE_FUNCTOR_UNARY_OPERATOR(negate, !) MAKE_FUNCTOR_UNARY_OPERATOR(bitNegate, ~) #undef MAKE_FUNCTOR_UNARY_OPERATOR /************************************************************/ /* */ /* functors for binary functions */ /* */ /************************************************************/ #define MAKE_FUNCTOR_BINARY_FUNCTION(function) \ using std::function; \ template \ struct Functor_##function; \ \ template \ struct ResultTraits0 > \ { \ typedef typename ResultTraits0::Res R1; \ typedef typename ResultTraits0::Res R2; \ typedef typename PromoteTraits::Promote R3; \ typedef typename NumericTraits::RealPromote Res; \ }; \ \ template \ struct ResultTraits1, T1> \ { \ typedef typename ResultTraits1::Res R1; \ typedef typename ResultTraits1::Res R2; \ typedef typename PromoteTraits::Promote R3; \ typedef typename NumericTraits::RealPromote Res; \ }; \ \ template \ struct ResultTraits2, T1, T2> \ { \ typedef typename ResultTraits2::Res R1; \ typedef typename ResultTraits2::Res R2; \ typedef typename PromoteTraits::Promote R3; \ typedef typename NumericTraits::RealPromote Res; \ }; \ \ template \ struct ResultTraits3, T1, T2, T3> \ { \ typedef typename ResultTraits3::Res R1; \ typedef typename ResultTraits3::Res R2; \ typedef typename PromoteTraits::Promote R3; \ typedef typename NumericTraits::RealPromote Res; \ }; \ \ template \ struct Functor_##function \ { \ Functor_##function(EXPR1 const & e1, EXPR2 const & e2) \ : expr1_(e1), expr2_(e2) \ {} \ \ typename ResultTraits0::Res \ operator()() const \ { \ return function(expr1_(), expr2_()); \ } \ \ template \ typename ResultTraits1::Res \ operator()(T const & v1) const \ { \ return function(expr1_(v1), expr2_(v1)); \ } \ \ template \ typename ResultTraits2::Res \ operator()(T1 const & v1, T2 const & v2) const \ { \ return function(expr1_(v1, v2), expr2_(v1, v2)); \ } \ \ template \ typename ResultTraits3::Res \ operator()(T1 const & v1, T2 const & v2, T3 const & v3) const \ { \ return function(expr1_(v1, v2, v3), expr2_(v1, v2, v3)); \ } \ \ private: \ \ EXPR1 expr1_; \ EXPR2 expr2_; \ }; \ \ template \ UnaryFunctor, UnaryFunctor > > \ function(UnaryFunctor const & e1, UnaryFunctor const & e2) \ { \ Functor_##function, UnaryFunctor > p(e1, e2); \ return UnaryFunctor, \ UnaryFunctor > >(p); \ } /************************************************************/ MAKE_FUNCTOR_BINARY_FUNCTION(pow) MAKE_FUNCTOR_BINARY_FUNCTION(atan2) MAKE_FUNCTOR_BINARY_FUNCTION(fmod) #undef MAKE_FUNCTOR_BINARY_FUNCTION /************************************************************/ #define MAKE_FUNCTOR_MINMAX(name, op) \ template \ struct Functor_##name; \ \ template \ struct ResultTraits0 > \ { \ typedef typename ResultTraits0::Res R1; \ typedef typename ResultTraits0::Res R2; \ typedef typename PromoteTraits::Promote Res; \ }; \ \ template \ struct ResultTraits1, T1> \ { \ typedef typename ResultTraits1::Res R1; \ typedef typename ResultTraits1::Res R2; \ typedef typename PromoteTraits::Promote Res; \ }; \ \ template \ struct ResultTraits2, T1, T2> \ { \ typedef typename ResultTraits2::Res R1; \ typedef typename ResultTraits2::Res R2; \ typedef typename PromoteTraits::Promote Res; \ }; \ \ template \ struct ResultTraits3, T1, T2, T3> \ { \ typedef typename ResultTraits3::Res R1; \ typedef typename ResultTraits3::Res R2; \ typedef typename PromoteTraits::Promote Res; \ }; \ \ template \ struct Functor_##name \ { \ Functor_##name(EXPR1 const & e1, EXPR2 const & e2) \ : expr1_(e1), expr2_(e2) \ {} \ \ typename ResultTraits0::Res \ operator()() const \ { \ typename \ ResultTraits0 >::R1 r1(expr1_()); \ typename \ ResultTraits0 >::R2 r2(expr2_()); \ return (r1 op r2) ? r1 : r2; \ } \ \ template \ typename ResultTraits1::Res \ operator()(T const & v1) const \ { \ typename \ ResultTraits1, T>::R1 r1(expr1_(v1)); \ typename \ ResultTraits1, T>::R2 r2(expr2_(v1)); \ return (r1 op r2) ? r1 : r2; \ } \ \ template \ typename ResultTraits2::Res \ operator()(T1 const & v1, T2 const & v2) const \ { \ typename \ ResultTraits2, T1, T2>::R1 r1(expr1_(v1, v2)); \ typename \ ResultTraits2, T1, T2>::R2 r2(expr2_(v1, v2)); \ return (r1 op r2) ? r1 : r2; \ } \ \ template \ typename ResultTraits3::Res \ operator()(T1 const & v1, T2 const & v2, T3 const & v3) const \ { \ typename \ ResultTraits3, T1, T2, T3>::R1 r1(expr1_(v1, v2, v3)); \ typename \ ResultTraits3, T1, T2, T3>::R2 r2(expr2_(v1, v2, v3)); \ return (r1 op r2) ? r1 : r2; \ } \ \ private: \ \ EXPR1 expr1_; \ EXPR2 expr2_; \ }; \ \ template \ UnaryFunctor, UnaryFunctor > > \ name(UnaryFunctor const & e1, UnaryFunctor const & e2) \ { \ Functor_##name, UnaryFunctor > p(e1, e2); \ return UnaryFunctor, \ UnaryFunctor > >(p); \ } MAKE_FUNCTOR_MINMAX(min, <) MAKE_FUNCTOR_MINMAX(max, >) #undef MAKE_FUNCTOR_MINMAX /************************************************************/ /* */ /* functors for binary operators */ /* */ /************************************************************/ #define MAKE_FUNCTOR_BINARY_OPERATOR(name, op) \ template \ struct Functor_##name; \ \ template \ struct ResultTraits0 > \ { \ typedef typename ResultTraits0::Res R1; \ typedef typename ResultTraits0::Res R2; \ typedef typename PromoteTraits::Promote Res; \ }; \ \ template \ struct ResultTraits1, T1> \ { \ typedef typename ResultTraits1::Res R1; \ typedef typename ResultTraits1::Res R2; \ typedef typename PromoteTraits::Promote Res; \ }; \ \ template \ struct ResultTraits2, T1, T2> \ { \ typedef typename ResultTraits2::Res R1; \ typedef typename ResultTraits2::Res R2; \ typedef typename PromoteTraits::Promote Res; \ }; \ \ template \ struct ResultTraits3, T1, T2, T3> \ { \ typedef typename ResultTraits3::Res R1; \ typedef typename ResultTraits3::Res R2; \ typedef typename PromoteTraits::Promote Res; \ }; \ \ template \ struct Functor_##name \ { \ Functor_##name(EXPR1 const & e1, EXPR2 const & e2) \ : expr1_(e1), expr2_(e2) \ {} \ \ typename ResultTraits0::Res \ operator()() const \ { \ return expr1_() op expr2_(); \ } \ \ template \ typename ResultTraits1::Res \ operator()(T const & v1) const \ { \ return expr1_(v1) op expr2_(v1); \ } \ \ template \ typename ResultTraits2::Res \ operator()(T1 const & v1, T2 const & v2) const \ { \ return expr1_(v1, v2) op expr2_(v1, v2); \ } \ \ template \ typename ResultTraits3::Res \ operator()(T1 const & v1, T2 const & v2, T3 const & v3) const \ { \ return expr1_(v1, v2, v3) op expr2_(v1, v2, v3); \ } \ \ private: \ \ EXPR1 expr1_; \ EXPR2 expr2_; \ }; \ \ template \ UnaryFunctor, UnaryFunctor > > \ operator op(UnaryFunctor const & e1, UnaryFunctor const & e2) \ { \ Functor_##name, UnaryFunctor > p(e1, e2); \ return UnaryFunctor, \ UnaryFunctor > >(p); \ } /************************************************************/ MAKE_FUNCTOR_BINARY_OPERATOR(add, +) MAKE_FUNCTOR_BINARY_OPERATOR(subtract, -) MAKE_FUNCTOR_BINARY_OPERATOR(multiply, *) MAKE_FUNCTOR_BINARY_OPERATOR(divide, /) MAKE_FUNCTOR_BINARY_OPERATOR(modulo, %) MAKE_FUNCTOR_BINARY_OPERATOR(bitAnd, &) MAKE_FUNCTOR_BINARY_OPERATOR(bitOr, |) MAKE_FUNCTOR_BINARY_OPERATOR(bitXor, ^) #undef MAKE_FUNCTOR_BINARY_OPERATOR /************************************************************/ #define MAKE_FUNCTOR_BINARY_OPERATOR_BOOL(name, op) \ template \ struct Functor_##name; \ \ template \ struct ResultTraits0 > \ { \ typedef bool Res; \ }; \ \ template \ struct ResultTraits1, T1> \ { \ typedef bool Res; \ }; \ \ template \ struct ResultTraits2, T1, T2> \ { \ typedef bool Res; \ }; \ \ template \ struct ResultTraits3, T1, T2, T3> \ { \ typedef bool Res; \ }; \ \ template \ struct Functor_##name \ { \ Functor_##name(EXPR1 const & e1, EXPR2 const & e2) \ : expr1_(e1), expr2_(e2) \ {} \ \ bool operator()() const \ { \ return expr1_() op expr2_(); \ } \ \ template \ bool operator()(T const & v1) const \ { \ return expr1_(v1) op expr2_(v1); \ } \ \ template \ bool operator()(T1 const & v1, T2 const & v2) const \ { \ return expr1_(v1, v2) op expr2_(v1, v2); \ } \ \ template \ bool operator()(T1 const & v1, T2 const & v2, T3 const & v3) const \ { \ return expr1_(v1, v2, v3) op expr2_(v1, v2, v3); \ } \ \ private: \ \ EXPR1 expr1_; \ EXPR2 expr2_; \ }; \ \ template \ UnaryFunctor, UnaryFunctor > > \ operator op(UnaryFunctor const & e1, UnaryFunctor const & e2) \ { \ Functor_##name, UnaryFunctor > p(e1, e2); \ return UnaryFunctor, \ UnaryFunctor > >(p); \ } /************************************************************/ MAKE_FUNCTOR_BINARY_OPERATOR_BOOL(equals, ==) MAKE_FUNCTOR_BINARY_OPERATOR_BOOL(differs, !=) MAKE_FUNCTOR_BINARY_OPERATOR_BOOL(less, <) MAKE_FUNCTOR_BINARY_OPERATOR_BOOL(lessEqual, <=) MAKE_FUNCTOR_BINARY_OPERATOR_BOOL(greater, >) MAKE_FUNCTOR_BINARY_OPERATOR_BOOL(greaterEqual, >=) MAKE_FUNCTOR_BINARY_OPERATOR_BOOL(and, &&) MAKE_FUNCTOR_BINARY_OPERATOR_BOOL(or, ||) #undef MAKE_FUNCTOR_BINARY_OPERATOR_BOOL /************************************************************/ /* */ /* unary apply */ /* */ /************************************************************/ template struct UnaryFctPtrFunctor { UnaryFctPtrFunctor(EXPR const & e, RES (*fct)(ARG)) : expr_(e), f_(fct) {} RES operator()() const { return f_(expr_()); } template RES operator()(T const & v1) const { return f_(expr_(v1)); } template RES operator()(T1 const & v1, T2 const & v2) const { return f_(expr_(v1, v2)); } template RES operator()(T1 const & v1, T2 const & v2, T3 const & v3) const { return f_(expr_(v1, v2, v3)); } protected: EXPR expr_; RES (*f_)(ARG); }; template struct ResultTraits0 > { typedef RES Res; }; template struct ResultTraits1, T1> { typedef RES Res; }; template struct ResultTraits2, T1, T2> { typedef RES Res; }; template struct ResultTraits3, T1, T2, T3> { typedef RES Res; }; template UnaryFunctor, RES, ARG> > applyFct(RES (*f)(ARG), UnaryFunctor const & e) { UnaryFctPtrFunctor, RES, ARG> p(e, f); return UnaryFunctor, RES, ARG> >(p); } /************************************************************/ /* */ /* binary apply */ /* */ /************************************************************/ template struct BinaryFctPtrFunctor { BinaryFctPtrFunctor(EXPR1 const & e1, EXPR2 const & e2, RES (*f)(ARG1, ARG2)) : expr1_(e1), expr2_(e2), f_(f) {} RES operator()() const { return f_(expr1_(), expr2_()); } template RES operator()(T const & v1) const { return f_(expr1_(v1), expr2_(v1)); } template RES operator()(T1 const & v1, T2 const & v2) const { return f_(expr1_(v1, v2), expr2_(v1, v2)); } template RES operator()(T1 const & v1, T2 const & v2, T3 const & v3) const { return f_(expr1_(v1, v2, v3), expr2_(v1, v2, v3)); } protected: EXPR1 expr1_; EXPR2 expr2_; RES (*f_)(ARG1, ARG2); }; template struct ResultTraits0 > { typedef RES Res; }; template struct ResultTraits1, T1> { typedef RES Res; }; template struct ResultTraits2, T1, T2> { typedef RES Res; }; template struct ResultTraits3, T1, T2, T3> { typedef RES Res; }; template UnaryFunctor, UnaryFunctor, RES, ARG1, ARG2> > applyFct(RES (*f)(ARG1, ARG2), UnaryFunctor const & e1, UnaryFunctor const & e2) { BinaryFctPtrFunctor, UnaryFunctor, RES, ARG1, ARG2> p(e1, e2, f); return UnaryFunctor, UnaryFunctor, RES, ARG1, ARG2> >(p); } /************************************************************/ /* */ /* comma operator */ /* */ /************************************************************/ template struct CommaFunctor { CommaFunctor(EXPR1 const & e1, EXPR2 const & e2) : expr1_(e1), expr2_(e2) {} typename ResultTraits0::Res operator()() const { expr1_(); return expr2_(); } template typename ResultTraits1::Res operator()(T const & v1) const { expr1_(v1); return expr2_(v1); } template typename ResultTraits2::Res operator()(T1 const & v1, T2 const & v2) const { expr1_(v1, v2); return expr2_(v1, v2); } template typename ResultTraits3::Res operator()(T1 const & v1, T2 const & v2, T3 const & v3) const { expr1_(v1, v2, v3); return expr2_(v1, v2, v3); } protected: EXPR1 expr1_; EXPR2 expr2_; }; 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 UnaryFunctor, UnaryFunctor > > operator,(UnaryAnalyser const & e1, UnaryFunctor const & e2) { CommaFunctor, UnaryFunctor > p(e1, e2); return UnaryFunctor, UnaryFunctor > >(p); } /************************************************************/ template struct CommaAnalyser { CommaAnalyser(EXPR1 const & e1, EXPR2 const & e2) : expr1_(e1), expr2_(e2) {} void operator()() const { expr1_(); expr2_(); } template void operator()(T const & v1) const { expr1_(v1); expr2_(v1); } template void operator()(T1 const & v1, T2 const & v2) const { expr1_(v1, v2); expr2_(v1, v2); } template void operator()(T1 const & v1, T2 const & v2, T3 const & v3) const { expr1_(v1, v2, v3); expr2_(v1, v2, v3); } protected: EXPR1 expr1_; EXPR2 expr2_; }; template UnaryAnalyser, UnaryAnalyser > > operator,(UnaryAnalyser const & e1, UnaryAnalyser const & e2) { CommaAnalyser, UnaryAnalyser > p(e1, e2); return UnaryAnalyser, UnaryAnalyser > >(p); } } // namespace functor template class FunctorTraits > : public FunctorTraitsBase > { public: typedef VigraTrueType isInitializer; typedef VigraTrueType isUnaryFunctor; typedef VigraTrueType isBinaryFunctor; typedef VigraTrueType isTernaryFunctor; }; template class FunctorTraits > : public FunctorTraitsBase > { public: typedef VigraTrueType isUnaryAnalyser; typedef VigraTrueType isBinaryAnalyser; typedef VigraTrueType isTernaryAnalyser; }; } // namespace vigra #endif /* NO_PARTIAL_TEMPLATE_SPECIALIZATION */ #endif // DOXYGEN #endif /* VIGRA_FUNCTOREXPRESSION_HXX */