Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: Using operator of two intrinsic types as a function object

I have a vector-like class that contains an array of objects of type "T", and I want to implement 4 arithmetic operators, which will apply the operation on each item:

// Constructors and other functions are omitted for brevity.
template<class T, unsigned int D>
class Vector {

public:
    // Add a value to each item: naive implementation.
    void operator += (const T&) {
        for (int i = 0; i < D; ++i) {
            data[i] += value;
        }
    }
    void operator -= (const T&) { ... }
    void operator *= (const T&) { ... }
    void operator /= (const T&) { ... }

private:
    T items[D];
};

Because operators will contain the same boilerplate code (looping over every element and applying appropriate operation), I thought I could generalize it:

template<class T, unsigned int D>
class Vector {

public:
    void operator += (const T& value) { do_for_each(???, value); }
    void operator -= (const T& value) { do_for_each(???, value); }
    void operator *= (const T& value) { do_for_each(???, value); }
    void operator /= (const T& value) { do_for_each(???, value); }

private:
    void
    do_for_each(std::binary_function<void, T, T>& op, T value) {
        std::for_each(data, data + D, std::bind2nd(op, value));
    }

    T data[D];
};

Now, the problem is, how do I pass an operator that takes two intrinsic types and returns void to do_for_each, as depicted in the example above? C++ does not let me do this trick for intrinsic types ("T::operator+=" will not work if "T" is "int").

like image 800
Alex B Avatar asked Nov 16 '08 03:11

Alex B


1 Answers

First, you should really return a reference from your operator+=, since you can later use them to implement operator+, operator- and so on. I will change that accordingly.

Also, your do_for_each has to be a template, since it has to know the precise type of the function object, as binary function objects are not polymorph classes. For the actual operation, you want to use std::transform:

template<class T, unsigned int D>
class Vector {

public:
    Vector& operator += (const T& value) { 
        do_for_each(std::plus<T>(), value); 
        return *this;
    }

    Vector& operator -= (const T& value) { 
        do_for_each(std::minus<T>(), value); 
        return *this;
    }

    Vector& operator *= (const T& value) { 
        do_for_each(std::multiplies<T>(), value);
        return *this; 
    }

    Vector& operator /= (const T& value) { 
        do_for_each(std::divides<T>(), value); 
        return *this;
    }

private:
    template<typename BinFun>
    void do_for_each(BinFun op, const T& value) {
        std::transform(data, data + D, data, std::bind2nd(op, value));
    }

    T data[D];
};

std::transform will just pass each element to the function object, and assigns the result back to the iterator given as the third argument.

like image 56
Johannes Schaub - litb Avatar answered Sep 30 '22 00:09

Johannes Schaub - litb