Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass an arithmetic operator to a template?

I want to somehow merge templates 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 Stupid "functors" are then used by another template. How can I avoid the repetition, WITHOUT the preprocessor? (The reason I got into templates was to avoid the preprocessor)

That is, how can I pass arithmetic operators into a template?

like image 994
OldCoder Avatar asked Dec 13 '22 01:12

OldCoder


1 Answers

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

I don't see any way to achieve what you're trying to do, except by using the preprocessor. Any good reasons for not wanting macros ?

If you want to make sure the return type is large enough to contains the result, you could do something along this way:

#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 metafunction, but you could write your own if metafunction if you cannot use Boost (class template parameterized by two types and a bool, specialized for true and false).

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

like image 55
Luc Touraille Avatar answered Jan 06 '23 10:01

Luc Touraille