I'm writing a matrix 3x3 class in c++.
glm::mat3 provides access to matrix data through the [][] operator syntax.
e.g. myMatrix[0][0] = 1.0f; would set the first row, first column entry to 1.0f.
I'd like to provide similar access. How can I overload the [][] operators?
I've tried the following, but I get errors:
operator name must be declared as a function
const real operator[][](int row, int col) const
{
// should really throw an exception for out of bounds indices
return ((row >= 0 && row <= 2) && (col >= 0 && col <= 2)) ? _data[row][col] : 0.0f;
}
What's the correct way to overload this operator?
There is no operator [][], so you need to overload the [] operator twice: once on the matrix, returning a surrogate object for the row, and once for the returned surrogate row:
// Matrix's operator[]
const row_proxy operator[](int row) const
{
return row_proxy(this, row);
}
// Proxy's operator[]
const real operator[](int col) const
{
// Proxy stores a pointer to matrix and the row passed into the first [] operator
return ((this->row >= 0 && this->row <= 2) && (col >= 0 && col <= 2)) ? this->matrix->_data[this->row][col] : 0.0f;
}
It would be easier to make the method double operator() (int row, int col) const. Instead of matrix[i][j] you just say matrix(i,j).
Generally, for multiple argument you want to use operator(), not operator[].
Hm, in case it wasn't obvious, there is no operator[][] in C++. It's just operator[] applied twice. Which means that if you want that notation, then you have to let the first one return a result (indexable thing or proxy) that the second can be applied to.
The code below sketches some approaches, choose what you like:
#include <iostream>
#include <vector>
template< int n >
int& dummy() { static int elem = n; return elem; }
struct Mat1
{
int operator() ( int const x, int const y ) const
{ return dummy<1>(); }
int& operator() ( int const x, int const y )
{ return dummy<1>(); }
Mat1( int, int ) {}
};
struct Mat2
{
int at( int const x, int const y ) const
{ return dummy<2>(); }
int& at( int const x, int const y )
{ return dummy<2>(); }
Mat2( int, int ) {}
};
struct Mat3
{
struct At { At( int x, int y ) {} };
int operator[]( At const i ) const
{ return dummy<3>(); }
int& operator[]( At const i )
{ return dummy<3>(); }
Mat3( int, int ) {}
};
class Mat4
{
protected:
int get( int const x, int const y ) const
{ return dummy<4>(); }
void set( int const x, int const y, int const v ) {}
class AssignmentProxy
{
private:
Mat4* pMat_;
int x_;
int y_;
public:
void operator=( int const v ) const
{ pMat_->set( x_, y_, v ); }
int value() const { return pMat_->get( x_, y_ ); }
operator int () const { return value(); }
AssignmentProxy( Mat4& mat, int const x, int const y )
: pMat_( &mat ), x_( x ), y_( y )
{}
};
public:
int operator()( int const x, int const y ) const
{ return get( x, y ); }
AssignmentProxy operator()( int const x, int const y )
{ return AssignmentProxy( *this, x, y ); }
Mat4( int, int ) {}
};
class Mat5
{
protected:
int at( int const x, int const y ) const
{ return dummy<4>(); }
int& at( int const x, int const y )
{ return dummy<5>(); }
class RowReadAccess
{
private:
Mat5 const* pMat_;
int y_;
public:
int operator[]( int const x ) const
{
return pMat_->at( x, y_ );
}
RowReadAccess( Mat5 const& m, int const y )
: pMat_( &m ), y_( y )
{}
};
class RowRWAccess
{
private:
Mat5* pMat_;
int y_;
public:
int operator[]( int const x ) const
{
return pMat_->at( x, y_ );
}
int& operator[]( int const x )
{
return pMat_->at( x, y_ );
}
RowRWAccess( Mat5& m, int const y )
: pMat_( &m ), y_( y )
{}
};
public:
RowReadAccess operator[]( int const y ) const
{ return RowReadAccess( *this, y ); }
RowRWAccess operator[]( int const y )
{ return RowRWAccess( *this, y ); }
Mat5( int, int ) {}
};
struct Mat6
{
private:
std::vector<int> elems_;
int width_;
int height_;
int indexFor( int const x, int const y ) const
{
return y*width_ + x;
}
public:
int const* operator[]( int const y ) const
{
return &elems_[indexFor( 0, y )];
}
int* operator[]( int const y )
{
return &elems_[indexFor( 0, y )];
}
Mat6( int const w, int const h )
: elems_( w*h, 6 ), width_( w ), height_( h )
{}
};
int main()
{
using namespace std;
enum{ w = 1024, h = 1024 };
typedef Mat3::At At;
Mat1 m1( w, h );
Mat2 m2( w, h );
Mat3 m3( w, h );
Mat4 m4( w, h );
Mat5 m5( w, h );
Mat6 m6( w, h );
wcout
<< m1( 100, 200 ) // No fuss simple, but exposes element ref.
<< m2.at( 100, 200 ) // For those who don't like operators.
<< m3[At( 100, 200)] // If you really want square brackets mnemonic.
<< m4( 100, 200 ) // Hides element ref by using assignment proxy.
<< m5[200][100] // Ditto but with square brackets (more complex).
<< m6[200][100] // The minimum fuss square brackets, exposes elem ref.
<< endl;
}
Oh well I discovered after posting that code that I haven't fully hidden the internal storage for Mat5: it needs an extra proxy level, as in Mat4. So that approach is really complex. I wouldn't do it (Mat1 is nice and easy I think), but some folks think proxys are cool, and data hiding even more cool…
Summing up, there is no “the” correct way to overload operator[]. There are many ways (as illustrated by the code above), each with some trade-offs. And generally you’re better off using operator(), because as opposed to operator[] it can take any number of arguments.
There is no [][] operator. The way GLM does it is by returning a vec3& from the first []. vec3 has its own [] operator overload. So it's two separate operator[]s on two separate classes.
This is also how GLSL works. The first [] gets the column as a vector. The second takes the vector and gets the value from it.
The expression foo[1][2] is really interpreted as (foo[1])[2], i.e. the [] operator is applied twice in succession starting with the variable foo. There is no [][] operator to be overloaded.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Currently I came across an interesting article what's called the Kronecker-Produkt. At the same time I'm working on my neural network library.
So that my algorithm works, I need a tensor class, where I can get the product of two tensor's with an overloaded * operator.
Consider the following example/questions:
How to efficiently construct/store the nested matrices?
How to perform the product of two tensor's?
How to visualize tensor c as simply as possible?
My class 3 tensor which currently only supports 3 dimensions:
#pragma once
#include <iostream>
#include <sstream>
#include <random>
#include <cmath>
#include <iomanip>
template<typename T>
class tensor {
public:
const unsigned int x, y, z, s;
tensor(unsigned int x, unsigned int y, unsigned int z, T val) : x(x), y(y), z(z), s(x * y * z) {
p_data = new T[s];
for (unsigned int i = 0; i < s; i++) p_data[i] = val;
}
tensor(const tensor<T> & other) : x(other.x), y(other.y), z(other.z), s(other.s) {
p_data = new T[s];
memcpy(p_data, other.get_data(), s * sizeof(T));
}
~tensor() {
delete[] p_data;
p_data = nullptr;
}
T * get_data() {
return p_data;
}
static tensor<T> * random(unsigned int x, unsigned int y, unsigned int z, T val, T min, T max) {
tensor<T> * p_tensor = new tensor<T>(x, y, z, val);
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_real_distribution<T> dist(min, max);
for (unsigned int i = 0; i < p_tensor->s; i++) {
T rnd = dist(mt);
while (abs(rnd) < 0.001) rnd = dist(mt);
p_tensor->get_data()[i] = rnd;
}
return p_tensor;
}
static tensor<T> * from(std::vector<T> * p_data, T val) {
tensor<T> * p_tensor = new tensor<T>(p_data->size(), 1, 1, val);
for (unsigned int i = 0; i < p_tensor->get_x(); i++) p_tensor->set_data(i + 0 * p_tensor->get_x() * + 0 * p_tensor->get_x() * p_tensor->get_y(), p_data->at(i));
return p_tensor;
}
friend std::ostream & operator <<(std::ostream & stream, tensor<T> & tensor) {
stream << "(" << tensor.x << "," << tensor.y << "," << tensor.z << ") Tensor\n";
for (unsigned int i = 0; i < tensor.x; i++) {
for (unsigned int k = 0; k < tensor.z; k++) {
stream << "[";
for (unsigned int j = 0; j < tensor.y; j++) {
stream << std::setw(5) << roundf(tensor(i, j, k) * 1000) / 1000;
if (j + 1 < tensor.y) stream << ",";
}
stream << "]";
}
stream << std::endl;
}
return stream;
}
tensor<T> & operator +(tensor<T> & other) {
tensor<T> result(*this);
return result;
}
tensor<T> & operator -(tensor<T> & other) {
tensor<T> result(*this);
return result;
}
tensor<T> & operator *(tensor<T> & other) {
tensor<T> result(*this);
return result;
}
T & operator ()(unsigned int i, unsigned int j, unsigned int k) {
return p_data[i + (j * x) + (k * x * y)];
}
T & operator ()(unsigned int i) {
return p_data[i];
}
private:
T * p_data = nullptr;
};
int main() {
tensor<double> * p_tensor_input = tensor<double>::random(6, 2, 3, 0.0, 0.0, 1.0);
tensor<double> * p_tensor_weight = tensor<double>::random(2, 6, 3, 0.0, 0.0, 1.0);
std::cout << *p_tensor_input << std::endl;
std::cout << *p_tensor_weight << std::endl;
tensor<double> p_tensor_output = *p_tensor_input + *p_tensor_weight;
return 0;
}
Your first step is #2 -- and get it correct.
After that, optimize.
Start with a container C<T>.
Define some operations on it. wrap(T) returns a C<T> containing that T. map takes a C<T> and a function on T U f(T) and returns C<U>. flatten takes a C<C<U>> and returns a C<U>.
Define scale( T, C<T> ) which takes a T and a C<T> and returns a C<T> with the elements scaled. Aka, scalar multiplication.
template<class T>
C<T> scale( T scalar, C<T> container ) {
return map( container, [&](T t){ return t*scalar; } );
}
Then we have:
template<class T>
C<T> tensor( C<T> lhs, C<T> rhs ) {
return flatten( map( lhs, [&](T t) { return scale( t, rhs ); } ) );
}
is your tensor product. And yes, that can be your actual code. I would tweak it a bit for efficiency.
(Note I used different terms, but I'm basically describing monadic operations using different words.)
After you have this, test, optimize, and iterate.
As for 3, the result of tensor products get large and complex, there is no simple visualization for a large tensor.
Oh, and keep things simple and store data in a std::vector to start.
Here are some tricks for efficient vectors i learned in class, but they should be equally good for a tensor.
Define an empty constructor and assignment operator. For example
tensor(unsigned int x, unsigned int y, unsigned int z) : x(x), y(y), z(z), s(x * y * z) {
p_data = new T[s];
}
tensor& operator=( tensor const& that ) {
for (int i=0; i<size(); ++i) {
p_data[i] = that(i) ;
}
return *this ;
}
template <typename T>
tensor& operator=( T const& that ) {
for (int i=0; i<size(); ++i) {
p_data[i] = that(i) ;
}
return *this ;
}
Now we can implement things like addition and scaling with deferred evaluation. For example:
template<typename T1, typename T2>
class tensor_sum {
//add value_type to base tensor class for this to work
typedef decltype( typename T1::value_type() + typename T2::value_type() ) value_type ;
//also add function to get size of tensor
value_type operator()( int i, int j, int k ) const {
return t1_(i,j,k) + v2_(i,j,k) ;
}
value_type operator()( int i ) const {
return t1_(i) + v2_(i) ;
}
private:
T1 const& t1_;
T2 const& t2_;
}
template <typename T1, typename T2>
tensor_sum<T1,T2> operator+(T1 const& t1, T2 const& t2 ) {
return vector_sum<T1,T2>(t1,t2) ;
}
This tensor_sum behaves exactly like any normal tensor, except that we don't have to allocate memory to store the result. So we can do something like this:
tensor<double> t0(...);
tensor<double> t1(...);
tensor<double> t2(...);
tensor<double> result(...); //define result to be empty, we will fill it later
result = t0 + t1 + 5.0*t2;
The compiler should optimize this to be just one loop, without storing intermediate results or modifying the original tensors. You can do the same thing for scaling and the kronecker product. Depending on what you want to do with the tensors, this can be a big advantage. But be careful, this isn't always the best option.
When implementing the kronecker product you should be careful of the of the ordering of your loop, try to go through the tensors in the order they are stored for cache efficiency.
I want to create an operator [] in the case of two dimensional vector. After searching, I have found that it's impossible to pass two arguments. How I can obtain the value of m_matrix[i][j] in the main?
relevant code:
class MyMatrix
{
public: // Methods
MyMatrix();
~MyMatrix();
int operator[] (int n);
private: // Attributes
int m_n;
int m_m;
std:: vector <std:: vector <int> > m_matrix;
};
int MyMatrix::operator[](int n, int m) // in the cpp
{
if (n>=0 && m>=0 && n<=m_n && m<=m_m)
{
return m_matrix[n-1][m-1];
}
else
{ cout<<"******************"<<endl;
cout<<"No valid index"<<endl;
cout<<"******************"<<endl;
return 0;
}
}
...
mat_test1[2][2]; // for example in the main
What's wrong with this?
To resume the comment, you may do:
class MyMatrix
{
public:
// Other methods
const std::vector<int>& operator[] (int m) const { return m_matrix.at(m); }
std::vector<int>& operator[] (int m) { return m_matrix.at(m); }
int operator () (int m, int n) const { return m_matrix.at(m).at(n); }
int& operator () (int m, int n) { return m_matrix.at(m).at(n); }
private:
std::vector<std::vector<int>> m_matrix;
};
Note: I used at instead of [] to use the check from vector and so it throws exception for out of bound access.
And then use it:
MyMatrix matrix(5, 4); // size of the matrix from constructor
matrix[0][1] = 42; // MyMatrix::operator [] followed by std::vector<int>::operator[]
matrix(2, 2) = 42; // MyMatrix::operator () (int, int);
Live example.
There are several ways, but in the end, they all come down to using a
proxy.
For various reasons, the usual implementation of a Matrix isn't
std::vector<std::vector<T>>, but simply std::vector<T>, with an
appropriate calculation of the index. In this case:
class Matrix
{
int myRows;
int myColumns;
std::vector<int> myData;
class Proxy
{
Matrix* myOwner;
int myRow;
public:
Proxy( Matrix* owner, int row )
: myOwner( owner )
, myRow( row )
{
}
int& operator[]( int column )
{
return myOwner->get( myRow, column );
}
};
public:
Matrix( int rows, int columns )
: myRows( rows )
, myColumns( columns )
, myData( rows * columns )
{
}
int& get( int row, int column )
{
assert( 0 <= row && row < myRows
&& 0 <= column && column < myColumns );
return myData[ row * myColumns + column ];
}
Proxy operator[]( int row ) { return Proxy( this, row ); }
};
In fact, you'll want a few more overloads (and possibly two proxies) to
handle const and non-const overloads. But this is the general pattern
for such things.
Be aware, too, that there are two conventions concerning such overloads.
One is to say that the [] returns a projection, and that the correct
solution for handling indexing into multi dimensional structures is to
overload operator() (which can be made to take an arbitrary number of
parameters). I personally prefer the [][] solution, but this
preference is not universal; a lot of people with a more mathematical
background prefer using ().
Background
Large application with a bundle of code, I can't change the storage mechanism.
I would like to create an iterator over a set of multi-dimensional data stored in parallel arrays so we can start using std algorithms & containers.
Any ideas on how to make this work correctly?
#include <boost/iterator/iterator_facade.hpp>
#include <iostream>
#include <algorithm>
class curve_point_iterator;
const int curve_size = 10;
class curve
{
public:
curve()
{
std::fill( x, &x[curve_size], 0.0 );
std::fill( y, &y[curve_size], 0.0 );
}
double x[curve_size];
double y[curve_size];
curve_point_iterator begin();
curve_point_iterator end();
};
class point_reference
{
public:
point_reference( double& x_, double& y_ )
: x( x_ )
, y( y_ )
{
}
point_reference& operator = ( point_reference& other )
{
x = other.x;
y = other.y;
return *this;
}
double & x;
double & y;
};
class curve_point_iterator
: public boost::iterator_facade<
curve_point_iterator
, point_reference
, boost::random_access_traversal_tag >
{
public:
curve_point_iterator()
: index(0)
, curve_(nullptr)
{}
explicit curve_point_iterator( curve* curve_in, size_t index_ = 0 )
: index( index_ )
, curve_( curve_in )
{}
private:
friend class boost::iterator_core_access;
void increment()
{
++index;
}
void decrement()
{
--index;
}
void advance( size_t n )
{
index += n;
}
difference_type distance_to( curve_point_iterator const& other ) const
{
return other.index - this->index;
}
bool equal(curve_point_iterator const& other) const
{
return this->index == other.index && this->curve_ == other.curve_;
}
point_reference& dereference() const
{
auto pt_ref = new( point_reference_buffer ) point_reference( curve_->x[index]
, curve_->y[index] );
return *pt_ref;
}
size_t index;
mutable char point_reference_buffer[sizeof(point_reference)];
curve* curve_;
};
curve_point_iterator curve::begin()
{
return curve_point_iterator( this );
}
curve_point_iterator curve::end()
{
return curve_point_iterator( this, curve_size+1 );
}
int main(int argc, char* argv[])
{
curve crv;
crv.x[1] = 20;
crv.x[2] = 10;
std::sort( crv.begin(), crv.end(), []( point_reference const& a, point_reference const& b )
{
return a.x < b.x;
});
for( auto i = 0; i < curve_size; ++i )
{
std::cout << crv.x[i] << std::endl;
}
return 0;
}
Output
0
20
20
20
20
20
20
20
20
20
After changing to
class point_reference
{
... ( all the other stuff )
double x; // no longer reference
double y; // no longer reference
};
Output
0
20
10
0
0
0
0
0
0
Okay, what you need to do is to introduce a point type (which has value semantics) in addition to point_reference, which has the reference semantics you're looking for. You need the value semantics so that operations such as swap act as the standard expects. You can use the fourth argument of iterator_facade to allow this. Also, this way there is no need to use that mutable buffer, since the point_reference itself is returned by value.
Also, your curve::end() used the wrong index, and should use curve_size as its index.
#include <boost/iterator/iterator_facade.hpp>
#include <iostream>
#include <algorithm>
class curve_point_iterator;
const int curve_size = 10;
class curve
{
public:
curve()
{
std::fill( x, &x[curve_size], 0.0 );
std::fill( y, &y[curve_size], 0.0 );
}
double x[curve_size];
double y[curve_size];
curve_point_iterator begin();
curve_point_iterator end();
};
class point
{
public:
point( const double& x_, const double& y_ )
: x( x_ )
, y( y_ )
{
}
double x;
double y;
};
class point_reference
{
public:
point_reference( double& x_, double& y_ )
: x( x_ ),
y( y_ )
{
}
point_reference& operator = ( const point& other )
{
x = other.x;
y = other.y;
return *this;
}
operator point() const
{
return point(x, y);
}
double & x;
double & y;
point_reference& operator=(const point_reference& other)
{
x = other.x;
y = other.y;
}
point_reference* operator->()
{
return this;
}
point_reference* operator->() const
{
return this;
}
};
class curve_point_iterator
: public boost::iterator_facade<
curve_point_iterator
, point
, boost::random_access_traversal_tag
, point_reference>
{
public:
curve_point_iterator()
: index(0)
, curve_(nullptr)
{}
explicit curve_point_iterator( curve* curve_in, size_t index_ = 0 )
: index( index_ )
, curve_( curve_in )
{}
point_reference operator->() const
{
return dereference();
}
private:
friend class boost::iterator_core_access;
void increment()
{
++index;
}
void decrement()
{
--index;
}
void advance( size_t n )
{
index += n;
}
difference_type distance_to( curve_point_iterator const& other ) const
{
return other.index - this->index;
}
bool equal(curve_point_iterator const& other) const
{
return this->index == other.index && this->curve_ == other.curve_;
}
point_reference dereference() const
{
// auto pt_ref = new( point_reference_buffer ) point_reference( curve_->x[index]
// , curve_->y[index] );
// return *pt_ref;
return point_reference(curve_->x[index], curve_->y[index]);
}
size_t index;
curve* curve_;
};
curve_point_iterator curve::begin()
{
return curve_point_iterator( this );
}
curve_point_iterator curve::end()
{
return curve_point_iterator( this, curve_size );
}
int main(int argc, char* argv[])
{
curve crv;
crv.x[1] = 20;
crv.x[2] = 10;
std::sort( crv.begin(), crv.end(), []( point const& a, point const& b )
{
return a.x < b.x;
});
for( auto i = 0; i < curve_size; ++i )
{
std::cout << crv.x[i] << std::endl;
}
return 0;
}
Output:
0
0
0
0
0
0
0
0
10
20
I would like to know if it is possible to create an actual functor object from a lambda expression. I don't think so, but if not, why?
To illustrate, given the code below, which sorts points using various policies for x and y coordinates:
#include <vector>
#include <functional>
#include <algorithm>
#include <iostream>
struct Point
{
Point(int x, int y) : x(x), y(y) {}
int x, y;
};
template <class XOrder, class YOrder>
struct SortXY :
std::binary_function<const Point&, const Point&, bool>
{
bool operator()(const Point& lhs, const Point& rhs) const
{
if (XOrder()(lhs.x, rhs.x))
return true;
else if (XOrder()(rhs.x, lhs.x))
return false;
else
return YOrder()(lhs.y, rhs.y);
}
};
struct Ascending { bool operator()(int l, int r) const { return l<r; } };
struct Descending { bool operator()(int l, int r) const { return l>r; } };
int main()
{
// fill vector with data
std::vector<Point> pts;
pts.push_back(Point(10, 20));
pts.push_back(Point(20, 5));
pts.push_back(Point( 5, 0));
pts.push_back(Point(10, 30));
// sort array
std::sort(pts.begin(), pts.end(), SortXY<Descending, Ascending>());
// dump content
std::for_each(pts.begin(), pts.end(),
[](const Point& p)
{
std::cout << p.x << "," << p.y << "\n";
});
}
The expression std::sort(pts.begin(), pts.end(), SortXY<Descending, Ascending>()); sorts according to descending x values, and then to ascending y values. It's easily understandable, and I'm not sure I really want to make use of lambda expressions here.
But if I wanted to replace Ascending / Descending by lambda expressions, how would you do it? The following isn't valid:
std::sort(pts.begin(), pts.end(), SortXY<
[](int l, int r) { return l>r; },
[](int l, int r) { return l<r; }
>());
This problem arises because SortXY only takes types, whereas lambdas are objects. You need to re-write it so that it takes objects, not just types. This is basic use of functional objects- see how std::for_each doesn't take a type, it takes an object.
I have posted a similar question w.r.t. lambda functors within classes.
Check this out, perhaps it helps:
Lambda expression as member functors in a class
I had a similar problem: It was required to provide in some cases a "raw"-function pointer and in other a functor. So I came up with a "workaround" like this:
template<class T>
class Selector
{
public:
Selector(int (*theSelector)(T& l, T& r))
: selector(theSelector) {}
virtual int operator()(T& l, T& r) {
return selector(l, r);
}
int (*getRawSelector() const)(T&, T&) {
return this->selector;
}
private:
int(*selector)(T& l, T& r);
};
Assuming you have two very simple functions taking --- as described --- either a functor or a raw function pointer like this:
int
findMinWithFunctor(int* array, int size, Selector<int> selector)
{
if (array && size > 0) {
int min = array[0];
for (int i = 0; i < size; i++) {
if (selector(array[i], min) < 0) {
min = array[i];
}
}
return min;
}
return -1;
}
int
findMinWithFunctionPointer(int* array, int size, int(*selector)(int&, int&))
{
if (array && size > 0) {
int min = array[0];
for (int i = 0; i < size; i++) {
if (selector(array[i], min) < 0) {
min = array[i];
}
}
return min;
}
return -1;
}
Then you would call this functions like this:
int numbers[3] = { 4, 2, 99 };
cout << "The min with functor is:" << findMinWithFunctor(numbers, 3, Selector<int>([](int& l, int& r) -> int {return (l > r ? 1 : (r > l ? -1 : 0)); })) << endl;
// or with the plain version
cout << "The min with raw fn-pointer is:" << findMinWithFunctionPointer(numbers, 3, Selector<int>([](int& l, int& r) -> int {return (l > r ? 1 : (r > l ? -1 : 0)); }).getRawSelector()) << endl;
Of course in this example there is no real benefit passing the int's as reference...it's just an example :-)
Improvements:
You can also modify the Selector class to be more concise like this:
template<class T>
class Selector
{
public:
typedef int(*selector_fn)(T& l, T& r);
Selector(selector_fn theSelector)
: selector(theSelector) {}
virtual int operator()(T& l, T& r) {
return selector(l, r);
}
selector_fn getRawSelector() {
return this->selector;
}
private:
selector_fn selector;
};
Here we are taking advantage of a simple typedef in order to define the function pointer once and use only it's name rather then writing the declaration over and over.
Need prettier solution of below example but with std::accumulate.
#include <algorithm>
#include <vector>
#include <iostream>
class Object
{
public:
Object( double a, double b ):
a_( a ),
b_( b )
{}
double GetA() const { return a_; }
double GetB() const { return b_; }
// other methods
private:
double a_;
double b_;
};
class Calculator
{
public:
Calculator( double& result ):
result_( result )
{}
void operator() ( const Object& object )
{
// some formula
result_ += object.GetA() * object.GetB();
}
private:
double& result_;
};
int main()
{
std::vector< Object > collection;
collection.push_back( Object( 1, 2 ) );
collection.push_back( Object( 3, 4 ) );
double result = 0.0;
std::for_each( collection.begin(), collection.end(),
Calculator( result ) );
std::cout << "result = " << result << std::endl;
return 0;
}
do changes in Calculator and main function.
struct Calculator
{
double operator() ( double result, const Object& obj )
{
return result + ( obj.GetA() * obj.GetB());
}
};
int main()
{
std::vector< Object > collection;
collection.push_back( Object( 1, 2 ) );
collection.push_back( Object( 3, 4 ) );
double result = std::accumulate( collection.begin(), collection.end(), 0, Calculator() );
std::cout << "result = " << result << std::endl;
return 0;
}
also it could be better:
double sumABProduct( double result, const Object& obj )
{
return result + ( obj.GetA() * obj.GetB());
}
double result = std::accumulate( collection.begin(), collection.end(), 0, sumABProduct );
Update 2: Boost.Lambda makes this a piece of cake:
// headers
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
using namespace boost::lambda;
// ...
cout << accumulate(dv.begin(), dv.end(),
0,
_1 += bind(&strange::value, _2)) //strange defined below
<< endl;
Update: This has been bugging me for a while. I can't just get any of the STL algorithms to work in a decent manner. So, I rolled my own:
// include whatever ...
using namespace std;
// custom accumulator that computes a result of the
// form: result += object.method();
// all other members same as that of std::accumulate
template <class I, class V, class Fn1, class Fn2>
V accumulate2(I first, I last, V val, Fn1 op, Fn2 memfn) {
for (; first != last; ++first)
val = op(val, memfn(*first));
return val;
}
struct strange {
strange(int a, int b) : _a(a), _b(b) {}
int value() { return _a + 10 * _b; }
int _a, _b;
};
int main() {
std::vector<strange> dv;
dv.push_back(strange(1, 3));
dv.push_back(strange(4, 6));
dv.push_back(strange(20, -11));
cout << accumulate2(dv.begin(), dv.end(),
0, std::plus<int>(),
mem_fun_ref(&strange::value)) << endl;
}
Of course, the original solution still holds:
The easiest is to implement an operator+. In this case:
double operator+(double v, Object const& x) {
return v + x.a_;
}
and make it a friend of Object or member (look up why you may prefer one over the other):
class Object
{
//...
friend double operator+(double v, Object const& x);
and you're done with:
result = accumulate(collection.begin(), collection.end(), 0.0);
My earlier approach doesn't work because we need a binary_function.
std::accumulate manual.
here is an issue here, I guess the arguments are written in the wrong order should be:
result = std::accumulate(collection.begin(), collection.end(), Object(0),Adapt())
where Adapt is defined thus:
struct Adapt {
static double mul(Object const &x) { return x.GetA() * x.GetB(); }
static Object operator()(Object const &x, Object const &y) {
return Object(mul(x)+mul(y)) ; } };
in this case of accumulate, the result is contained in a returned Object.
If you are using gnu parallel mode the functor will give you problems if the result and the actual object referred to by the iterator are different.
struct Adapt {
static double mul(Object const &x) { return x.GetA() * x.GetB(); }
static double operator()(Object const &x, Object const &y) {
return mul(x)+mul(y) ; } };
result = std::accumulate(collection.begin(), collection.end(), 0.0,Adapt())
will not work with gnu parallel mode for some strange and silly reason.
Using c++0x:
#include <numeric>
#include <vector>
#include <iostream>
class Object
{
public:
Object( double a, double b ):
a_( a ),
b_( b )
{}
double GetA() const { return a_; }
double GetB() const { return b_; }
// other methods
private:
double a_;
double b_;
};
int main()
{
std::vector< Object > collection;
collection.push_back( Object( 1, 2 ) );
collection.push_back( Object( 3, 4 ) );
double result = std::accumulate( collection.begin(), collection.end(), 0,
[] (double result, const Object& obj)
{
return result + obj.GetA() * obj.GetB();
}
);
std::cout << "result = " << result << std::endl;
return 0;
}
One would hope this is homework...
struct Adapt {
static double mul(Object const &x) { return x.GetA() * x.GetB(); }
static double operator()(Object const &x, Object const &y) {
return mul(x)+mul(y); } };
and
result = std::accumulate(collection.begin(), collection.end(), Object(0,0),Adapt() );
assuming you're not allowed to touch the declaration of Object.