I am using a deque so I can generate rolling averages and variances for my data. I store n and n^2 as a pair in the deque and then use accumulate with my own operator+().
#include <deque>
#include <numeric>
#include <utility>
template <typename T1, typename T2>
std::pair<T1,T2> operator+(const std::pair<T1,T2>& lhs, const std::pair<T1,T2>& rhs)
{
return std::pair<T1,T2>(lhs.first + rhs.first, lhs.second + rhs.second);
}
namespace resource
{
template <typename T>
class rollingStats
{
public:
rollingStats(unsigned int n, const T& val):
xs(n, std::pair<T,T>(val, val*val))
{;}
~rollingStats()
{;}
T getMean(void) const
{
std::pair<T,T> sum = std::accumulate(xs.begin(), xs.end(), std::pair<T,T>((T)0,(T)0));
return sum.first / xs.size();
}
T getVar(void) const
{
const unsigned int n = xs.size();
std::pair<T,T> sum = std::accumulate(xs.begin(), xs.end(), std::pair<T, T > ((T)0,(T)0));
return ((n * sum.second - sum.first*sum.first) / (n * n));
}
void addValue(const T& val)
{
xs.pop_front();
xs.push_back(std::pair<T,T>(val,val*val) );
}
const std::deque<std::pair<T,T> >& getXs(void) const {return xs;}
private:
std::deque<std::pair<T,T> > xs;
};
}
I get a compilation error using g++ 4.1.2 which I can't resolve.
[ CC ] resource/UnitTest: rollingStats_Test.o
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_numeric.h: In function ‘_Tp std::accumulate(_InputIterator, _InputIterator, _Tp) [with _InputIterator = std::_Deque_iterator<std::pair<float, float>, const std::pair<float, float>&, const std::pair<float, float>*>, _Tp = std::pair<float, float>]’:
../rollingStats.hpp:45: instantiated from ‘T resource::rollingStats<T>::getMean() const [with T = float]’
rollingStats_Test.cpp:98: instantiated from here
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_numeric.h:89: error: no match for ‘operator+’ in ‘__init + __first.std::_Deque_iterator<_Tp, _Ref, _Ptr>::operator* [with _Tp = std::pair<float, float>, _Ref = const std::pair<float, float>&, _Ptr = const std::pair<float, float>*]()’
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_bvector.h:267: note: candidates are: std::_Bit_iterator std::operator+(ptrdiff_t, const std::_Bit_iterator&)
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_bvector.h:353: note: std::_Bit_const_iterator std::operator+(ptrdiff_t, const std::_Bit_const_iterator&)
make: *** [rollingStats_Test.o] Error 1
What have I got wrong here? Do I need to add my own functor instead of relying on the STL alone?
thanks
std::pair doesn't have an operator+, and you haven't provided a way for std::accumulate to call your implementation of operator+.
I would wrap the functionality you provided in operator+ in a functor...
template <typename T1, typename T2> struct pair_sum : public std::binary_function< std::pair<T1,T2>, std::pair<T1,T2>, std::pair<T1,T2> >
{
std::pair<T1,T2> operator()(const std::pair<T1,T2>& lhs, const std::pair<T1,T2>& rhs)
{
return std::pair<T1,T2>(lhs.first + rhs.first, lhs.second + rhs.second);
}
};
...and use that by calling the version of std::accumulate that takes 4 arguments:
std::pair<T,T> sum = std::accumulate(xs.begin(), xs.end(), std::make_pair((T)0,(T)0), pair_sum<T,T>());
Quoting Oliver Seiler's comment:
I can see three options: use the form of accumulate that takes a binary function, using an add_pair function you'd need to write (probably the simplest option); subclass std::pair and give it addition operators (feels dirty); add a new struct/class that either has a pair or just has the members you need, and use that instead of the pair (probably the most flexible option).
[This is a community wiki answer. Feel free to edit to add corrections, samples, etc.]
You can get sum of pairs with help of boost::lambda:
#include <boost/lambda/bind.hpp>
#include <boost/lambda/construct.hpp>
template<typename T>
void summarize()
{
typedef std::pair<T, T> pt_t;
std::deque<pt_t> xs;
using namespace boost::lambda;
// fill xs with useful stuff
pt_t res = std::accumulate(
xs.begin(), xs.end(), std::make_pair(T(),T()),
bind( constructor<pt_t>(),
bind( std::plus<T>(), bind(&pt_t::first,_1), bind(&pt_t::first,_2) ),
bind( std::plus<T>(), bind(&pt_t::second,_1), bind(&pt_t::second,_2) )
) );
}
Related
I tried to use std::reduce with a functor to calculate the number of characters in an array. GCC gives an error, while it compiles and works in MSVC. link here
#include <iostream>
#include <array>
#include <numeric>
#include <cstring>
int main()
{
std::array arr{ "Mickey","Minnie","Jerry" };
struct StringLength
{
auto operator()(const char* l, size_t r)
{
return strlen(l) + r;
}
auto operator()(size_t l, const char* r)
{
return l + strlen(r);
}
auto operator()(const char* l, const char* r)
{
return strlen(l) + strlen(r);
}
auto operator()(size_t l, size_t r)
{
return l + r;
}
};
std::cout << std::reduce(arr.begin(), arr.end(), size_t{}, StringLength());
// this ^ works in MSVC
}
GCC 10.1 error because important information should not be hidden behind a link:
/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/numeric:
In instantiation of '_Tp std::reduce(_InputIterator, _InputIterator, _Tp, _BinaryOperation)
[with _InputIterator = const char**; _Tp = long unsigned int;
_BinaryOperation = main()::StringLength]':
<source>:29:78: required from here
/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/numeric:263:21: error:
static assertion failed
263 | static_assert(is_convertible_v<value_type, _Tp>);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I agree with dewaffled that this is a bug. The libstdc++ implementation of std::reduce looks like this:
template<typename InputIt, typename Tp, typename BinOp>
Tp reduce(InputIt first, InputIt last, Tp init, BinOp binary_op) {
using value_type = typename iterator_traits<InputIt>::value_type;
static_assert(is_invocable_r_v<Tp, BinOp&, Tp&, Tp&>);
static_assert(is_convertible_v<value_type, Tp>);
// ...
}
I wasn't able to find a requirement in the standard that iterator's value_type has to be convertible into Tp. Moreover, this requirement is not necessary at all. If you remove that static assert, your code will compile just fine as it should.
Update from GCC Bugzilla
Fixed for 9.5, 10.4 and 11.2.
Jonathan Wakely, 2021-06-18
I've got a template class containing a priority queue of other classes, I need to use the priority overloader to call the individual class overloaders to compare based on the individual classes preferences (in this case it's age, in another class it could be price.
I've got absolutely no doubt that I've implemented the operator overloading incorrect so would appreciate the advice.
For example
#include <iostream>
#include <queue>
#include <string>
using namespace std;
class Animal {
public:
Animal();
Animal(string t, int a);
int get_age()const;
bool operator< ( Animal& b) const;
void display()const;
private:
string type;
double age;
};
void Animal::display() const
{
cout << "Type: " << type << " Age: " << age;
}
int Animal::get_age() const
{
return age;
}
Animal::Animal(){}
Animal::Animal(string t, int a)
{
type = t;
age = a;
}
bool Animal::operator< ( Animal& b) const
{
return b.get_age();
}
template<typename T>
class Collection {
public:
Collection();
Collection(string n, string d);
void add_item(const T& c);
private:
priority_queue <T> pets;
string name; // Name of the collection
string description; // Descriptions of the collection
};
template<typename T>
Collection<T>::Collection(){}
template<typename T>
Collection<T>::Collection(string n, string d)
{
name = n;
description = d;
}
template<typename T>
bool operator<(const T& one, const T& two)
{
return one.operator<(two);
}
template<typename T>
void Collection<T>::add_item(const T& c)
{
pets.push(c);
}
int main(){
Animal p1("Dog", 10);
Animal p2("Cat", 5);
Animal p3("Turtle", 24);
Collection<Animal> P("Pets", "My Pets");
P.add_item(p1);
P.add_item(p2);
P.add_item(p3);
cout << endl;
return 0;
}
I get this error and I'm not sure what I need to do to fix it. I've got to keep the class overloader as the single variable (Animal& b).
task.cpp: In instantiation of 'bool operator<(const T&, const T&)
[with T = Animal]':
c:\mingw-4.7.1\bin../lib/gcc/mingw32/4.7.1/include/c++/bits/stl_function.h:237:22:
required from 'bool std::less<_Tp>::operator()(const _Tp&, const _Tp&)
const [with _Tp = Animal]'
c:\mingw-4.7.1\bin../lib/gcc/mingw32/4.7.1/include/c++/bits/stl_heap.h:310:4: required from 'void std::__adjust_heap(_RandomAccessIterator,
_Distance, _Distance, _Tp, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator > >; _Distance = int; _Tp = Animal; _Compare =
std::less]'
c:\mingw-4.7.1\bin../lib/gcc/mingw32/4.7.1/include/c++/bits/stl_heap.h:442:4: required from 'void std::make_heap(_RandomAccessIterator,
_RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator > >; _Compare = std::less]'
c:\mingw-4.7.1\bin../lib/gcc/mingw32/4.7.1/include/c++/bits/stl_queue.h:393:9: required from 'std::priority_queue<_Tp, _Sequence,
_Compare>::priority_queue(const _Compare&, const _Sequence&) [with _Tp = Animal; _Sequence = std::vector >; _Compare = std::less]' task.cpp:57:45: required from 'Collection::Collection(std::string, std::string) [with T = Animal;
std::string = std::basic_string]' task.cpp:79:43: required
from here task.cpp:66:30: error: no matching function for call to
'Animal::operator<(const Animal&) const' task.cpp:66:30: note:
candidate is: task.cpp:36:6: note: bool Animal::operator<(Animal&)
const task.cpp:36:6: note: no known conversion for argument 1 from
'const Animal' to 'Animal&' task.cpp: In function 'bool
operator<(const T&, const T&) [with T = Animal]':
Your comparison
bool Animal::operator< ( Animal& b) const
{
return b.get_age(); // returns true always unless age == 0
}
is no comparison and it should take a const parameter. You should have something like
bool Animal::operator< (const Animal& b) const
// ^----------------------- const !
{
return get_age() < b.get_age();
}
Btw you dont need to use a member operator< for the priority queue. Especially if you want to sort objects in different ways I would recommend to not use it, but pass a lambda to the priority_queue. See eg here for an example.
Both of your overloads of < are problematic
bool Animal::operator< ( Animal& b) const
the Animal should also be const. You also need to compare both parameters, otherwise things (such as your priority_queue) that expect < to provide an ordering will have undefined behaviour.
You don't use anything non-public from Animal, so I suggest you change it to
bool operator< (const Animal & lhs, const Animal & rhs)
{ return lhs.get_age() < rhs.get_age(); }
This has the benefit of treating both sides identically, rather than one being implicit.
template<typename T>
bool operator<(const T& one, const T& two)
{
return one.operator<(two);
}
This template matches all types and is entirely superfluous. a < b can call either a member or a free operator <. Just delete this template.
I have a std::set container whose elements are objects of the following class:
class LaneConnector {
public:
const Lane* getLaneFrom() const {
return From;
}
const Lane* getLaneTo() const {
return To;
}
private:
Lane* From;
Lane* To;
}
and my comparator function is as follows:
struct MyLaneConectorSorter {
bool operator() (LaneConnector * c, LaneConnector * d)
{
Lane* a = const_cast<Lane*>(c->getLaneFrom());
Lane* b = const_cast<Lane*>(d->getLaneFrom());
return (a->getLaneID() < b->getLaneID());
}
} myLaneConnectorSorter;
Now when I try to sort the elements in the set with:
//dont panic, the container just came through a const_iterator of a std::map :)
const std::set<LaneConnector*> & tempLC = (*it_cnn).second;
std::sort(tempLC.begin(), tempLC.end(), myLaneConnectorSorter);
I get a frenzy of errors starting with the following lines, Appreciate if you help me solve this problem.
Thanks:
/usr/include/c++/4.6/bits/stl_algo.h: In function ‘void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = std::_Rb_tree_const_iterator<LaneConnector*>, _Compare = {anonymous}::MyLaneConectorSorter]’:
/home/.../dev/Basic/shared/conf/simpleconf.cpp:1104:65: instantiated from here
/usr/include/c++/4.6/bits/stl_algo.h:5368:4: error: no match for ‘operator-’ in ‘__last - __first’
/usr/include/c++/4.6/bits/stl_algo.h:5368:4: note: candidates are:
/usr/include/c++/4.6/bits/stl_iterator.h:321:5: note: template<class _Iterator> typename std::reverse_iterator::difference_type std::operator-(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_Iterator>&)
/usr/include/c++/4.6/bits/stl_iterator.h:378:5: note: template<class _IteratorL, class _IteratorR> typename std::reverse_iterator<_IteratorL>::difference_type std::operator-(const std::reverse_iterator<_IteratorL>&, const std::reverse_iterator<_IteratorR>&)
/usr/include/c++/4.6/bits/stl_bvector.h:181:3: note: std::ptrdiff_t std::operator-(const std::_Bit_iterator_base&, const std::_Bit_iterator_base&)
/usr/include/c++/4.6/bits/stl_bvector.h:181:3: note: no known conversion for argument 1 from ‘std::_Rb_tree_const_iterator<LaneConnector*>’ to ‘const std::_Bit_iterator_base&’
First, you cannot sort an std::set. It is a sorted structure, sorting happens upon construction or insertion.
Second, you can construct an std::set with your own sorting functor, and you can avoid unnecessary const_casts by making it take const pointers:
struct MyLaneConectorSorter {
bool operator() (const LaneConnector* lhs, const LaneConnector* rhs) const
{
// you may want to put some null pointer checks in here
const Lane* a = lhs->getLaneFrom();
const Lane* b = rhs->getLaneFrom();
return a->getLaneID() < b->getLaneID();
}
};
and instantiate the set like this:
std::set<LaneConnector*, MyLaneConectorSorter> s(MyLaneConectorSorter());
or, if you want to construct it from a different set, with a different ordering,
std::set<LaneConnector*> orig = ..... ;
....
std::set<LaneConnector*, MyLaneConectorSorter> s(orig.begin(), orig.end(), MyLaneConectorSorter());
I have a set of shared_ptr, and I'd like to use remove_copy_if with a custom function object for the predicate. I didn't know the "best" way to do it. Right now, I've got this working:
class CellInCol : public std::unary_function<const std::shared_ptr<Cell>,
bool>
{
public:
CellInCol( size_t col ) : _col( col ) {}
bool operator() ( const std::shared_ptr<Cell> &a ) const
{
return ( a->GetX() == _col );
}
private:
size_t _col;
};
typedef std::set<std::shared_ptr<Cell>, CellSorter> Container;
Container _grid;
// initialization omitted...
Puzzle::Container Puzzle::GetCol( size_t c )
{
Cell::Validate( c, 1, 9 );
Container col;
std::remove_copy_if( _grid.begin(), _grid.end(),
std::inserter( col, col.begin() ),
std::not1( CellInCol( c ) ) );
return col;
}
I decided to do const references to shared_ptr because the object won't hold on to the pointer and this just seemed more efficient than an extra copy of the shared_ptr.
It seems like it would be better to just take const references to the objects, but I couldn't get it to compile. I changed it to this, but no luck:
class CellInCol : public std::unary_function<const Cell,
bool>
{
public:
CellInCol( size_t col ) : _col( col ) {}
// note use of const ref to shared_ptr's
bool operator() ( const Cell &a ) const
{
return ( a.GetX() == _col );
}
private:
size_t _col;
};
Here is the output from g++:
In file included from /usr/include/c++/4.4/algorithm:62,
from /usr/include/c++/4.4/valarray:41,
from Puzzle.h:5,
from Puzzle.cpp:2:
/usr/include/c++/4.4/bits/stl_algo.h: In function ‘_OIter std::remove_copy_if(_IIter, _IIter, _OIter, _Predicate) [with _IIter = std::_Rb_tree_const_iterator<std::shared_ptr<Sudoku::Cell> >, _OIter = std::insert_iterator<std::set<std::shared_ptr<Sudoku::Cell>, Sudoku::CellSorter, std::allocator<std::shared_ptr<Sudoku::Cell> > > >, _Predicate = std::unary_negate<Sudoku::<unnamed>::CellInRow>]’:
Puzzle.cpp:100: instantiated from here
/usr/include/c++/4.4/bits/stl_algo.h:938: error: no match for call to ‘(std::unary_negate<Sudoku::<unnamed>::CellInRow>) (const std::shared_ptr<Sudoku::Cell>&)’
/usr/include/c++/4.4/bits/stl_function.h:357: note: candidates are: bool std::unary_negate<_Predicate>::operator()(const typename _Predicate::argument_type&) const [with _Predicate = Sudoku::<unnamed>::CellInRow]
/usr/include/c++/4.4/bits/stl_algo.h: In function ‘_OIter std::remove_copy_if(_IIter, _IIter, _OIter, _Predicate) [with _IIter = std::_Rb_tree_const_iterator<std::shared_ptr<Sudoku::Cell> >, _OIter = std::insert_iterator<std::set<std::shared_ptr<Sudoku::Cell>, Sudoku::CellSorter, std::allocator<std::shared_ptr<Sudoku::Cell> > > >, _Predicate = std::unary_negate<Sudoku::<unnamed>::CellInCol>]’:
Puzzle.cpp:110: instantiated from here
/usr/include/c++/4.4/bits/stl_algo.h:938: error: no match for call to ‘(std::unary_negate<Sudoku::<unnamed>::CellInCol>) (const std::shared_ptr<Sudoku::Cell>&)’
/usr/include/c++/4.4/bits/stl_function.h:357: note: candidates are: bool std::unary_negate<_Predicate>::operator()(const typename _Predicate::argument_type&) const [with _Predicate = Sudoku::<unnamed>::CellInCol]
/usr/include/c++/4.4/bits/stl_algo.h: In function ‘_OIter std::remove_copy_if(_IIter, _IIter, _OIter, _Predicate) [with _IIter = std::_Rb_tree_const_iterator<std::shared_ptr<Sudoku::Cell> >, _OIter = std::insert_iterator<std::set<std::shared_ptr<Sudoku::Cell>, Sudoku::CellSorter, std::allocator<std::shared_ptr<Sudoku::Cell> > > >, _Predicate = std::unary_negate<Sudoku::<unnamed>::CellInBlock>]’:
Puzzle.cpp:121: instantiated from here
/usr/include/c++/4.4/bits/stl_algo.h:938: error: no match for call to ‘(std::unary_negate<Sudoku::<unnamed>::CellInBlock>) (const std::shared_ptr<Sudoku::Cell>&)’
/usr/include/c++/4.4/bits/stl_function.h:357: note: candidates are: bool std::unary_negate<_Predicate>::operator()(const typename _Predicate::argument_type&) const [with _Predicate = Sudoku::<unnamed>::CellInBlock]
/usr/include/c++/4.4/bits/stl_algo.h: In function ‘_OIter std::remove_copy_if(_IIter, _IIter, _OIter, _Predicate) [with _IIter = std::_Rb_tree_const_iterator<std::shared_ptr<Sudoku::Cell> >, _OIter = std::insert_iterator<std::set<std::shared_ptr<Sudoku::Cell>, Sudoku::CellSorter, std::allocator<std::shared_ptr<Sudoku::Cell> > > >, _Predicate = std::unary_negate<Sudoku::<unnamed>::CellIsNeighbor>]’:
Puzzle.cpp:154: instantiated from here
/usr/include/c++/4.4/bits/stl_algo.h:938: error: no match for call to ‘(std::unary_negate<Sudoku::<unnamed>::CellIsNeighbor>) (const std::shared_ptr<Sudoku::Cell>&)’
/usr/include/c++/4.4/bits/stl_function.h:357: note: candidates are: bool std::unary_negate<_Predicate>::operator()(const typename _Predicate::argument_type&) const [with _Predicate = Sudoku::<unnamed>::CellIsNeighbor]
make: *** [Puzzle.o] Error 1
Is there another way to do it, or any suggestions?
First of all, since you're using the C++0x features (std::shared_ptr), it makes sense to use std::copy_if() to avoid having to call std::not1.
The first functor you wrote works, and a minimal compilable example would be something like this: https://ideone.com/XhuNu
The second functor does not work, as the compiler points out, due to mismatch between its argument_type (which is const Cell) and the argument that it is being called with, which is const std::shared_ptr<Cell>&.
It's simply not what the container contains! For all it knows at this point, those Cell objects may not even be copyable.
The second functor would indeed be a better thing to use if the container is a set of Cells, not a set of shared pointers to Cells. It is considered good design to avoid shared ownership of objects anyway.
Example code that would compile with the second functor
#include <set>
#include <functional>
#include <algorithm>
#include <iostream>
struct Cell {
int mX;
Cell(int x) : mX(x) {}
size_t GetX() const { return mX;}
};
struct CellSorter {
bool operator()(const Cell& l, const Cell& r) const
{
return l.GetX() < r.GetX();
}
};
// your second functor begins
class CellInCol : public std::unary_function<const Cell,
bool>
{
public:
CellInCol( size_t col ) : _col( col ) {}
// note use of const ref to shared_ptr's
bool operator() ( const Cell &a ) const
{
return ( a.GetX() == _col );
}
private:
size_t _col;
};
// your second functor ends
int main()
{
typedef std::set<Cell, CellSorter> Container;
Container _grid = {Cell(1), Cell(2), Cell(7), Cell(10)};
Container col;
size_t c = 7;
std::remove_copy_if( _grid.begin(), _grid.end(),
std::inserter( col, col.begin() ),
std::not1( CellInCol( c ) ) );
std::cout << "col has " << col.size() << " elements\n"
<< "the first element is " << col.begin()->GetX() << '\n';
}
test run: https://ideone.com/kLiFn
You could use boost::make_indirect_iterator to make std::remove_copy_if work on the Cells instead of the shared_ptrs. However, since the algorithm would be working on the Cells directly, the output iterator would also have to take Cells and not shared_ptrs. Which means the output collection would have to be a collection of Cells.
If you want to store shared_ptrs, you'd have to transform the predicate somehow. You can use boost::lambda to do just that.
Cubbi's example modified to use boost::lambda:
#include <memory>
#include <set>
#include <functional>
#include <algorithm>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
struct Cell {
int mX;
Cell(int x) : mX(x) {}
size_t GetX() const { return mX;}
};
struct CellSorter {
bool operator()(const boost::shared_ptr<Cell>& l, const boost::shared_ptr<Cell>& r) const
{
return l->GetX() < r->GetX();
}
};
class CellInCol : public std::unary_function<Cell, bool>
{
public:
CellInCol( size_t col ) : _col( col ) {}
// note use of const ref to shared_ptr's
bool operator() ( const Cell &a ) const
{
return ( a.GetX() == _col );
}
private:
size_t _col;
};
int main()
{
typedef std::set<boost::shared_ptr<Cell>, CellSorter> Container;
Container _grid;
_grid.insert( boost::shared_ptr<Cell>(new Cell(1)));
_grid.insert( boost::shared_ptr<Cell>(new Cell(2)));
_grid.insert( boost::shared_ptr<Cell>(new Cell(7)));
_grid.insert( boost::shared_ptr<Cell>(new Cell(10)));
Container col;
size_t c = 7;
std::remove_copy_if(
_grid.begin(),
_grid.end(),
std::inserter( col, col.begin() ),
!boost::lambda::bind(CellInCol(c), *boost::lambda::_1) // <------ :^)
);
std::cout << "col has " << col.size() << " elements\n"
<< " the first element is " << (*col.begin())->GetX() << '\n';
}
(ideone's C++0x compiler doesn't know it's boost, so I changed std::shared_ptr to boost::shared_ptr, but that should make no difference)
http://www.ideone.com/mtMUj
ps:
I decided to do const references to shared_ptr because the object won't hold on to the pointer and this just seemed more efficient than an extra copy of the shared_ptr.
Yes, you should (almost) always pass shared_ptrs as reference-to-const, it makes a huge difference. Copying a shared_ptr on a platform with threads means at least one atomic instruction (CAS, atomic-increment or something similar), and those can be rather expensive. (And of course destroying the copy will be equally expensive)
The only exception I can think of would be if the function will copy the shared_ptr. In that case you could either take it by value and use swap() to "copy" it, or provide an rvalue-reference overload. (If the function doesn't always copy the shared_ptr, the rvalue-reference overload would be the preferred solution).
Of course it doesn't make a big difference if the function is expensive anyway, but if it's a very cheap function that might get inlined and is called in a thight loop, the difference can be quite noticeable.
I cannot figure out why this segment gives unresolved overloaded function error (gcc version 4.3.4 (Debian 4.3.4-6)):
#include <algorithm>
#include <boost/function.hpp>
// this does not work
int main1()
{
typedef boost::function<const int&(const int&, const int&)> max;
max m(&std::max<int>);
}
// this does not work
int main2() {
typedef boost::function2<const int&, const int&, const int&> max;
max m(static_cast<max>(&std::max<int>));
}
can you help me, thanks
test.cpp: In function âint main()â:
test.cpp:7: error: no matching function for call to âboost::function2<const int&, const int&, const int&>::function2(<unresolved overloaded function type>)â
/usr/include/boost/function/function_template.hpp:747: note: candidates are: boost::function2<R, T1, T2>::function2(const boost::function2<R, T1, T2>&) [with R = const int&, T0 = const int&\
, T1 = const int&]
/usr/include/boost/function/function_template.hpp:739: note: boost::function2<R, T1, T2>::function2(boost::function2<R, T1, T2>::clear_type*) [with R = const int&, T0 = cons\
t int&, T1 = const int&]
/usr/include/boost/function/function_template.hpp:707: note: boost::function2<R, T1, T2>::function2() [with R = const int&, T0 = const int&, T1 = const int&]
max/min is defined as
template<typename _Tp>
inline const _Tp&
max(const _Tp& __a, const _Tp& __b)
{
// concept requirements
__glibcxx_function_requires(_LessThanComparableConcept<_Tp>)
//return __a < __b ? __b : __a;
if (__a < __b)
return __b;
return __a;
}
I have tried all sorts of template explicit instantiation but nothing seems to work. Same problem appears with g++ 4.1 but not with ICC
this works
#include <algorithm>
#include <boost/function.hpp>
namespace std_ {
template<typename _Tp>
inline const _Tp&
max(const _Tp& __a, const _Tp& __b)
{
// concept requirements
//return __a < __b ? __b : __a;
if (__a < __b)
return __b;
return __a;
}
}
int main()
{
typedef const int &T;
typedef boost::function<T(T,T)> min_;
//typedef const int&(*min_)(const int&, const int&);
min_ m(::std_::max<int>);
}
and this
#include <algorithm>
#include <boost/function.hpp>
int main()
{
//typedef const int &T;
//typedef boost::function<T(T,T)> min_;
typedef const int&(*min_)(const int&, const int&);
min_ m(::std::max<int>);
}
Update: this is a gcc bug that has been fixed in gcc >=4.4. bugzilla. Also, revised my answer with a reduced test case.
There are two components to this problem: the way boost::function adopts a function pointer and the gcc bug.
boost::function - There is something strange about the error message you listed in the question; there is no candidate constructor that accepts anything like a function address. Digging into the boost::function src, the relevant constructor is (leaving out the enable_if argument):
template<typename Functor>
function(Functor f) : base_type(f) {}
So boost::function doesn't help you out at all in specifying the type of a function pointer; if the function is overloaded the address must be cast to specify its type. If an overloaded function address is used, the above template can't be instantiated, and therefore the appropriate constructor doesn't show up in the error message.
gcc bug - If you look at the stl_algobase.h header again, you'll see there are two templates named max, a two param version and a one param version. This shouldn't be a problem with you code though, right? The term &max<int> should instantiate the single param version and take its address. However, that is not what happens. You can see the problem in the reduced (no header) test case:
template <class T>
const T& max(const T& x, const T& y){
return x > y ? x : y;
}
template <class T, class C>
const T& max(const T& x, const T& y, C comp){
return comp(x, y) ? y : x;
}
template <class R, class A0, class A1>
struct functor{
template <class F>
functor(F f) : f(f) {}
R (*f)(A0, A1);
};
int main(void){
functor<const int&, const int&, const int&> func(&max<int>);
return 0;
}
The above code results in a unresolved overloaded function type with gcc 4.3.4. The fix is either to remove the template <class T, class C> max(...){...} definition or add a static_cast<const int& (*)(const int&, const int&)>(...) around the function address. I'm guessing the problem has to do with incorrect application of partial explicit parameter specification, which is specified by the standard. It lets you leave out trailing template parameters to do things like specify a return value type and not the argument types. That is, the compiler instantiates both template when it should only instantiate the fully specified template. Its moot speculation though, since the bug has been fixed in gcc >= 4.4.
Since one shouldn't hack at stl_algobase.h ;) , the work around Vicente suggests is the correct one, namely cast the function pointer to the desired function pointer type const int& (*)(const int&, const int&). In your code, the cast doesn't work because, as GMan points out, you are casting to a boost::function<...>, which does nothing to resolve the function pointer ambiguity.
To critique the code, there's no reason to static_cast that. Consider all the cast is going to do is use the constructor of boost::function2 to make a new boost::function2, then it will be copy-constructed into m. Just construct directly into m:
#include <algorithm>
#include <boost/function.hpp>
int main()
{
typedef boost::function2<const int&, const int&, const int&> max;
max m(&std::max<int>);
}
Lastly, the preferred syntax of boost::function is:
#include <algorithm>
#include <boost/function.hpp>
int main()
{
typedef boost::function<const int&(const int&, const int&)> max;
max m(&std::max<int>);
}
The n-ary specific classes are for older compiler support.
It seems to be a problem with the definition of the std::max template function with releases of gcc < 4.4
With gcc-4.4.0 and msvc Express9 it works.
The following works also for gcc-3.4 and gcc-4.3
int main1()
{
int res = std::max(1,2);
typedef boost::function<const int&(const int&, const int&)> max;
max m(static_cast<const int&(*)(const int&, const int&)>(std::max<int>));
return 0
}