template function object for accumulate

E

er

hi,
pls i need help with
a) understanding the error at the bottom of the code
b) making another function object, (almost) identical to
Accumulate_op, say Accumulate_const_op whose operator is defined as R
operator()(R sum_so_far,const C& obj)const
what would be the best way? i'm hoping i can create a more general
Accumulate_op with an extra par to specify if C& should be const or
not.


//here is the code:

template<typename C,typename R,R (C::*F)()> class Accumulate_op:
public std::binary_function<R,C,R>{//,typename R (C::*F)()
public:
Accumulate_op(){};
R operator()(R sum_so_far,C& obj)const;
};
template<typename C,typename R,R (C::*F)()> R
Accumulate_op<C,R,F>::eek:perator()(R sum_so_far,C& obj)const{
return sum_so_far+(obj.*F)();
};

class Test{
public:
Test(){};
long double get(){return 0.9;};
};

int main(){
Test t;
std::vector<Test> vec(3);
vec.push_back(t);
vec.push_back(t);
vec.push_back(t);

std::cout<<
std::accumulate(
vec.begin,
vec.end(),
0.0,
Accumulate_op<Test,long double,&Test::get>()
)<<std::endl;//error shows here
return 0;
}
//end of code

error: conversion from '<unresolved overloaded function type>' to
non-scalar type '__gnu_cxx::__normal_iterator<Test*,
std::vector<Test,
std::allocator<Test> > >' requested
 
E

er

hi,
pls i need help with
a) understanding the error at the bottom of the code
b) making another function object, (almost) identical to
Accumulate_op, say Accumulate_const_op whose operator is defined as R
operator()(R sum_so_far,const C& obj)const
what would be the best way? i'm hoping i can create a more general
Accumulate_op with an extra par to specify if C& should be const or
not.

//here is the code:

template<typename C,typename R,R (C::*F)()> class Accumulate_op:
public std::binary_function<R,C,R>{//,typename R (C::*F)()
public:
Accumulate_op(){};
R operator()(R sum_so_far,C& obj)const;
};
template<typename C,typename R,R (C::*F)()> R
Accumulate_op<C,R,F>::eek:perator()(R sum_so_far,C& obj)const{
return sum_so_far+(obj.*F)();
};

class Test{
public:
Test(){};
long double get(){return 0.9;};
};

int main(){
Test t;
std::vector<Test> vec(3);
vec.push_back(t);
vec.push_back(t);
vec.push_back(t);

std::cout<<
std::accumulate(
vec.begin,
vec.end(),
0.0,
Accumulate_op<Test,long double,&Test::get>()
)<<std::endl;//error shows here
return 0;
}
//end of code

error: conversion from '<unresolved overloaded function type>' to
non-scalar type '__gnu_cxx::__normal_iterator<Test*,
std::vector<Test,
std::allocator<Test> > >' requested

well a) is no longer a problem. there was a typo in the code:
vec.begin() instead of vec.begin
 
V

Victor Bazarov

er said:
pls i need help with
a) understanding the error at the bottom of the code
b) making another function object, (almost) identical to
Accumulate_op, say Accumulate_const_op whose operator is defined as R
operator()(R sum_so_far,const C& obj)const
what would be the best way? i'm hoping i can create a more general
Accumulate_op with an extra par to specify if C& should be const or
not.

See below.
//here is the code:

template<typename C,typename R,R (C::*F)()> class Accumulate_op:
public std::binary_function<R,C,R>{//,typename R (C::*F)()
public:
Accumulate_op(){};
R operator()(R sum_so_far,C& obj)const;
};
template<typename C,typename R,R (C::*F)()> R
Accumulate_op<C,R,F>::eek:perator()(R sum_so_far,C& obj)const{
return sum_so_far+(obj.*F)();
};

class Test{
public:
Test(){};
long double get(){return 0.9;};
};

int main(){
Test t;
std::vector<Test> vec(3);
vec.push_back(t);
vec.push_back(t);
vec.push_back(t);

So, your total number of vector elements is 6 here...
std::cout<<
std::accumulate(
vec.begin,
vec.end(),
0.0,
Accumulate_op<Test,long double,&Test::get>()
)<<std::endl;//error shows here
return 0;
}
//end of code

error: conversion from '<unresolved overloaded function type>' to
non-scalar type '__gnu_cxx::__normal_iterator<Test*,
std::vector<Test,
std::allocator<Test> > >' requested

OK, you solved this one. Here is what I propose:
===================================================================
class Test {
public:
long double get() { return 0.9; }
};

class TestConst {
public:
long double get() const { return 0.9; }
};

#include <numeric>
#include <vector>
#include <iostream>

template<typename C, typename R, typename Ff>
class Accumulate_op_T {
Ff F;
public:
Accumulate_op_T(Ff f) : F(f) {}
R operator()(R sum_so_far, C& obj) const
{
return sum_so_far + (obj.*F)();
}
};

template<typename C, typename R, typename Ff>
Accumulate_op_T<C,R,Ff> Accumulate_op(Ff f) {
return Accumulate_op_T<C,R,Ff>(f);
}

int main(){
Test t;
std::vector<Test> vec(3, t);
TestConst tc;
std::vector<TestConst> vecc(4, tc);

std::cout
<< std::accumulate(
vec.begin(),
vec.end(),
0.0,
Accumulate_op<Test, long double>(&Test::get))
<< std::endl;
std::cout
<< std::accumulate(
vecc.begin(),
vecc.end(),
0.0,
Accumulate_op<TestConst, long double>(&TestConst::get))
<< std::endl;
return 0;
}
===================================================================

V
 
V

Victor Bazarov

er said:
by the way, why does it work? is there a name for this?

I am sorry, you removed all context when you posted this,
why does *what* work? Is there name for *what*?

V
 
E

er

I am sorry, you removed all context when you posted this,
why does *what* work? Is there name for *what*?

V

below is my code and your correction to overcome the possibility that
*Ff be a const member function, and it achieves that goal. it's just
not obvious to me how it works. if you or anyone else could explain a
little that would be nice. thanks!

//code that gen error: could not convert template argument
'&TestConst::get' to 'double (TestConst::*)()')
//but it works with Test

template<typename C,typename R,R (C::*F)()>
class Accumulate_op_v1: public std::binary_function<R,C,R>{
public:
My_accumulate_op(){};
R operator()(R sum_so_far,C& obj)const;
};
template<typename C,typename R,R (C::*F)()>
R Accumulate_op_v1<C,R,F>::eek:perator()(R sum_so_far,C& obj)const{
return sum_so_far+(obj.*F)();
};

//code that works with a const C&
template<typename C, typename R, typename Ff>
class Accumulate_op_T {
Ff F;
public:
Accumulate_op_T(Ff f) : F(f) {}
R operator()(R sum_so_far, C& obj) const
{
return sum_so_far + (obj.*F)();
}

};

template<typename C, typename R, typename Ff>
Accumulate_op_T<C,R,Ff> Accumulate_op_v2(Ff f) {
return Accumulate_op_T<C,R,Ff>(f);
}

//main
int main(){
Test t;
std::vector<Test> vec(3, t);
TestConst tc;
std::vector<TestConst> vecc(4, tc);

std::cout
<< std::accumulate(
vec.begin(),
vec.end(),
0.0,
Accumulate_op_v2<Test, long double>(&Test::get))
<< std::endl;
std::cout
<< std::accumulate(
vecc.begin(),
vecc.end(),
0.0,
Accumulate_op_v2<TestConst, long
double>(&TestConst::get))
<< std::endl;
return 0;
}
 
V

Victor Bazarov

er said:
below is my code and your correction to overcome the possibility that
*Ff be a const member function, and it achieves that goal. it's just
not obvious to me how it works. if you or anyone else could explain a
little that would be nice. thanks!

//code that gen error: could not convert template argument
'&TestConst::get' to 'double (TestConst::*)()')
//but it works with Test

template<typename C,typename R,R (C::*F)()>

You specified the third argument too strictly. It prevents using
a member function declared 'const'. What I've suggested has no
such restriction.
class Accumulate_op_v1: public std::binary_function<R,C,R>{
public:
My_accumulate_op(){};
R operator()(R sum_so_far,C& obj)const;
};
template<typename C,typename R,R (C::*F)()>
R Accumulate_op_v1<C,R,F>::eek:perator()(R sum_so_far,C& obj)const{
return sum_so_far+(obj.*F)();
};

//code that works with a const C&
template<typename C, typename R, typename Ff>

Here 'Ff' can be essentially /anything/. The only limitation
imposed on it comes from the use of 'F'. It has to be a member
of the 'C' type (since it's used through the 'obj' reference to
an object of type 'C'), and it has to be callable without any
arguments (since none are supplied in the expression).
class Accumulate_op_T {
Ff F;
public:
Accumulate_op_T(Ff f) : F(f) {}
R operator()(R sum_so_far, C& obj) const
{
return sum_so_far + (obj.*F)();
}

};

template<typename C, typename R, typename Ff>
Accumulate_op_T<C,R,Ff> Accumulate_op_v2(Ff f) {

The type 'Ff' is *deduced* from the argument you pass to this
funciton. The proper template is instantiated and the temporary
object is created and used. Since in this case you never have
to spell out what type 'Ff' is, it becomes possible to use the
code with either a const member function or a non-const one.
return Accumulate_op_T<C,R,Ff>(f);
}

//main
int main(){
Test t;
std::vector<Test> vec(3, t);
TestConst tc;
std::vector<TestConst> vecc(4, tc);

std::cout
<< std::accumulate(
vec.begin(),
vec.end(),
0.0,
Accumulate_op_v2<Test, long double>(&Test::get))
<< std::endl;
std::cout
<< std::accumulate(
vecc.begin(),
vecc.end(),
0.0,
Accumulate_op_v2<TestConst, long
double>(&TestConst::get))
<< std::endl;
return 0;
}

V
 
E

er

thanks!

You specified the third argument too strictly. It prevents using
a member function declared 'const'. What I've suggested has no
such restriction.



Here 'Ff' can be essentially /anything/. The only limitation
imposed on it comes from the use of 'F'. It has to be a member
of the 'C' type (since it's used through the 'obj' reference to
an object of type 'C'), and it has to be callable without any
arguments (since none are supplied in the expression).


The type 'Ff' is *deduced* from the argument you pass to this
funciton. The proper template is instantiated and the temporary
object is created and used. Since in this case you never have
to spell out what type 'Ff' is, it becomes possible to use the
code with either a const member function or a non-const one.






V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top