How to pass arithmetic operator to a template?

I want to somehow combine patterns like these into one:

template <class Result, class T1, class T2> class StupidAdd { public: T1 _a; T2 _b; StupidAdd(T1 a, T2 b):_a(a),_b(b) {} Result operator()() { return _a+_b; } }; template <class Result, class T1, class T2> class StupidSub { public: T1 _a; T2 _b; StupidSub(T1 a, T2 b):_a(a),_b(b) {} Result operator()() { return _a-_b; } }; 

(followed by the same code for Mul, Div, etc.), where all the code is the same except for the actual "+", "-" (and "StupidAdd", "StupidSub", etc.).

These silly "functors" are then used by another template. How can I avoid repetition WITHOUT a preprocessor? (The reason I got into the templates was to avoid the preprocessor)

That is, how can I pass arithmetic operators to a pattern?

+4
source share
4 answers

Perhaps you could use std::plus<T> , std::minus<T> , std::multiplies<T> and std::divides<T> . However, they will only work if both operands are of the same type or, possibly, if the left can be converted to the type of the first.

I see no way to achieve what you are trying to do, except using a preprocessor. Any good reason for not wanting macros?

If you want to make sure that the return type is large enough to contain the result, you can do something like this:

 #include <functional> #include <boost/mpl/if_.hpp> // Metafunction returning the largest type between T and U // Might already exist in Boost but I can't find it right now...maybe // boost::math::tools::promote_args template <typename T, typename U> struct largest : boost::mpl::if_< boost::mpl::bool_<(sizeof(T) > sizeof(U))>, T, U > {}; template <typename T, typename U, template <typename S> class Op> struct Foo { typedef typename largest<T, U>::type largeType; largeType bar(const T & t, const U & u) { return Op<largeType>()(t, u); // Applies operator+ } }; int main() { Foo<int, double, std::plus> f; double d = f.bar(12, 13.0); // takes int and double, returns double } 

Here I used Boost MPL to write the largest metafile, but you could write your own if metafile if you cannot use Boost (a template template parameterized by two types and a bool specialized for true and false).

To determine the type of return expression, you can also look at boost :: result_of , which, if I understand correctly, is equivalent to the upcoming decltype operator in C ++ 0x.

+7
source

Thanks Luke, this is very cool. I finally made it easier:

 #include <functional> template < class Result, class T1, class T2, template <class ReturnType> class BinaryOp> class Stupido { public: T1 _a; T2 _b; Stupido(T1 a, T2 b):_a(a),_b(b) {} Result operator()() { return BinaryOp<Result>()((Result)_a,(Result)_b); } }; 

And used the plus, minus when creating Stupido. The reduction to "Result" was enough for my needs (int + double => double + double => double)

+3
source

I think the improvement for OldCoder solution:

 #include <functional> template <class Result, template <class Result> class BinaryOp> struct Stupido { template <typename T1, typename T2> Result operator()(const T1& a, const T2& b) { return BinaryOp<Result>()((Result)a,(Result)b); } }; 

Thus, a call can be made as:

 Stupido<int, std::plus > stup; int result = stup(3.0f, 2.0); 

and the same functional object can be used with multiple operands, so it can be passed to the std::transform call.

I believe there should be a way to remove one result from the template declaration, but I cannot find it.

+3
source

I would use a C ++ 0x type definition and a new auto definition. You will still need to define classes, but with their help you can better define them. They will still work enough to determine, but at least their use will be much cleaner. In particular, you can use decltype / auto to output the correct return type instead of explicitly specifying it.

They are available with a large number of recent compilers - Intel C ++, g ++, Comeau, beta version of VC ++ 2010 and even the most recent iteration of the name Borland / Inprise / Embarcadero / this week.

0
source

All Articles