I need someone who explain me these lines of code - c++

I need someone who explain me this code, line by line. I specially don't understand this line:
operator std::map<T, U>()
Thank you very much.
template <typename T, typename U>
class create_map
{
std::map<T, U> m_map;
public:
create_map(const T& key, const U& val)
{
m_map[key] = val;
}
create_map<T, U>& operator()(const T& key, const U& val)
{
m_map[key] = val;
return *this;
}
operator std::map<T, U>()
{
return m_map;
}
};

operator std::map<T, U>()
{
return m_map;
}
This is user-defined conversion function.
That means, you can write this:
//obj is an object of type create_map
create_map<int,std::string> obj(1,"Nawaz");
//obj implicitly converts into std::map type!
std::map<int,std::string> map_inst=obj;
See this topic to know more about user-defined conversion function:
User Defined Conversions in C++
You can see this as well: Implicit conversion sequences (C++ only)
create_map<T, U>& operator()(const T& key, const U& val)
{
m_map[key] = val;
return *this;
}
This actually overloads the operator(), which internally inserts or updates (key,val) pair into the m_map; just see the function definition as to what it does.
So using this function you can write code like this,
obj(2,"Sarfaraz"); //this inserts the pair into the underlying m_map;
I would also suggest you to explore std::map a bit more, especially the overloaded operator[] in std::map.

Code:
template <typename T, typename U>
class create_map
{
std::map<T, U> m_map;
public:
create_map(const T& key, const U& val)
{
m_map[key] = val;
}
create_map<T, U>& operator()(const T& key, const U& val)
{
m_map[key] = val;
return *this;
}
operator std::map<T, U>()
{
return m_map;
}
};
The purpose of this code is to be able to specify a map with specific key/value pairs, by chaining calls to operator(), like
create_map<int, std::string>( 1, "blah" )( 2, "hah" )( 3, "doh" )
Since the class does not have a default constructor, there's no way to use it to create an empty map. That may be by design. Or it may be a design error.
The
operator std::map<T, U>()
{
return m_map;
}
defines a conversion to std::map<T, U>, which is the end result of it all.
It can be invoked implicitly wherever a create_map is specified and a std::map is expected, such as using a create_map expression as argument in a function call.
However, it can be pretty inefficient since it copies the map. The compiler may well optimize away the copying. But it’s ungood to needlessly rely on Quality Of Implementation (although sometimes that is the best that one can do).
So it should instead be
operator std::map<T, U> const& () const
{
return m_map;
}
The const at the end there allows a create_map to be declared as const and used.
With this conversion to reference there is the same problem as with using reference arguments, namely a theoretical possibility of aliasing, where code that retains a reference to const is not prepared to deal with changes of the referred object. But in practice it’s not a problem. For example, as formal argument one just writes std::string const& s (instead of just std::string s) as a matter of course, and very few if any errors result from that – I’ve never experienced any problem.
Cheers & hth.,

There's not much to understand about it. operator std::map<T, U>() overrides the class' conversion operator (which takes no parameters) to provide an object instance of type std::map<T, U>. std::map is a STL standard class for associative key->value storage. In your case it maps from keys of type T to values of type U. T and U have been undefined so far (you wrote template class, but where are the template parameters?)
The conversion operator allows to use the class instance in place of the type the operator provides conversion for, like this.
class foo {
operator char const *() {
return "foo instance as char const *";
}
};
// ...
void bar(foo &f)
{
// here the class instance is used as if it were a char const *
cout << f << endl;
}

The line
operator std::map<T, U>()
defines a function that will be called when your create_map object is used like an std::map somewhere in the code.
An easier example would be:
class A
{
public:
operator int()
{
return 3;
}
};
int main()
{
A a;
cout << a << endl;
}
Now the computer finds out that it doesn't know how to print variable a, but it knows how to convert it to an int and then print it. So "3" gets printed.

Related

How to store a function object without resorting to std::function?

I am trying to make a generic container that would hold objects and their position:
class Vector;
template <typename T>
class Container
{
public:
void insert(const T& t)
{
insertAtPosition(t.getPosition() ,t);
}
private:
void insertAtPosition(const Vector& v, const T& t);
...
} ;
But what if the users' object position getter is not called getPosition?
How can I make this container generic with respect to the way in which the container internally obtains the position of an item?
So far, I have considered 3 approaches, none of them ideal:
Add a std::function<const Vector& (const T& t)> member to the Container.
This is a clean C++ solution, but this function is going to be called very very often and it may result in noticeable performance decrease.
Add a functor object to the container:
class Vector;
template <typename T, typename TGetPosition>
class Container
{
public:
Container(TGetPosition getPosition): getPosition_(getPosition){}
void insert(const T& t)
{
insertAtPosition(getPosition_(t) ,t);
}
private:
void insertAtPosition(const Vector& v, const T& t);
TGetPosition getPosition_;
} ;
I can use the object generator idiom to make it possible to use lambdas:
template <typename T, typename TGetPosition>
Container<T, TGetPosition> makeContainer(TGetPosition getter)
{
return Container<T, TGetPosition>(getter);
}
...
auto container = makeSimpleContainer<Widget>([](const Widget& w)
{
return w.tellMeWhereYourPositionMightBe();
});
There would be no performance overhead, but it would be impossible to get the type of such a container in certain contexts. For example, you could not create a class that would take such a container as a parameter, since decltype would not work, because lambdas cannot be used in unevaluated contexts.
Use #define GETTER getPosition and the user would just change getPosition to whatever he likes. There are so many things wrong with this approach that I don't even know where to start.
Please, is there some other way to do this? Did I miss anything. Any guidance is most welcome!
EDIT:
Regarding solution 2: I have no idea how could we get a the type of a container created with a lambda function. One way would be:
using TContainer = decltype(makeSimpleContainer<Widget>([](const Widget& w)
{
return w.tellMeWhereYourPositionMightBe();
});)
But this doesn't work, because lambdas cannot be used in unevaluated contexts.
Reasonably usable option would be to expect the context to have position_for():
template <class T> struct Container {
size_t insert(T const& x) {
insertAtPosition(position_for(x), x);
}
};
Vector const& position_for(const Widget& w) {
return ...;
}
Container<Widget> c;
c.insert(Widget());
...but designs where the container generates key from the business object usually do not fly well, as to lookup the object one would need to do a dummy one, which may be expensive.
It seems like your second solution will work even if you need to make a class holding a container:
template <typename Container>
struct SomeClass {
SomeClass(const Container &container) : container(container) { }
Container container;
};
int main()
{
auto container = makeSimpleContainer<Widget>([](const Widget& w)
{
return w.tellMeWhereYourPositionMightBe();
});
SomeClass<decltype(container)> test(container);
}

C++ operator[] overloading with template accessing boost::variant

I've this class with a map attribute which values are boost::variant.
typedef boost::variant<char, int, bool, unsigned short, float, timeval, double > MultiType;
class A {
public:
template<class T>
T& operator[](const std::string& key) {
return boost::get<T>(map_[key]);
}
template<class T>
std::string keyTypeToString(const std::string& key) {
std::stringstream ss;
ss << boost::get<T>(map_[key]);
return ss.str();
}
private:
std::map<std::string, MultiType> map_;
};
From main:
A a;
a["param"];
Compiler report this errors:
../src/main.cpp:8:25: error: no match for ‘operator[]’ in ‘a["param"]’
../src/main.cpp:8:25: note: candidate is:
../src/util/A.h:53:5: note: template T& A::operator[](const string&)
Maybe I'm missing something trivial, but I can't understand where I'm wrong..
Start with this:
template<class T>
T& get(const std::string& key) {
return boost::get<T>(map_[key]);
}
You call this like a.get<int>("hello"), where it will get the element "hello" as an int.
Next, write this:
struct pseudo_ref {
std::string const& str;
A* a;
template<typename T>
operator T&()&&{
return a->get<T>(str);
}
template<typename T>
pseudo_ref operator=( T&& t ) && {
a->get<typename std::decay<T>::type>(str) = std::forward<T>(t);
return {str, a};
}
pseudo_ref(pseudo_ref const&)=delete;
pseudo_ref& operator=(pseudo_ref const&)=delete;
pseudo_ref( std::string const& s, A* a_ ):str(s), a(a_) {}
};
then back in A:
pseudo_ref operator[](std::string const& str) {
return {str, this};
}
and we get [] that magically converts for you, so long as you assign to it/read from it using the exactly correct type.
This is somewhat dangerous, but cool.
If you want a const pseudo_ref, you need another class to represent it (with no = and operator T const& instead of operator T&).
In practice, this kind of malarkey is rarely worth it.
I wrote this in C++11, because writing it in C++03 is slightly more painful (and runs into lifetime issues with pseudo_ref -- they still exist if you have an auto&& x = a["hello"]), and less pain is good.
class A {
public:
class proxy {
friend class A;
private:
MultiType& it;
proxy(MultiType& it): it(it) {}
public:
template<typename T>
operator T&() {
return boost::get<T>(it);
}
};
proxy operator[](const std::string& key) {
return proxy(map_[key]);
}
private:
std::map<std::string, MultiType> map_;
};
EXPLANATION:
I can see that Yakk was trying similar thing. I have encapsulated the MultiType& from map_[key] in the proxy and then left the work on conversion (type-cast) operator. That's all.
Simple a[""] without assignment gets you the proxy.
double d = a["double"] will try to convert the proxy to double and thus call proxy::operator double&() (I had to test it because I was not sure if the type deduction will work as it is or will need some more work - well, it works!)
AFTERNOTE: It was not clear from the question and code provided what operations are allowed. We can modify the proxy to allow other operations or make it more readonly by changing the signature of type-conversion operator to return const T& instead.
Allowing modification leads to question: why not using MultiType& directly? (returning it from A::operator[]) And that leads to question: why class A at all?
AFTERNOTE #2: boost::variant does not have type-conversion operator and there must have been a reason for it. Think about this code:
int i = a["double"]
Runtime exception! I think that best solution would be to sub-class the MultiType and define type-conversion operator there (while checking boost::variant::which()).
ASSIGNING TO ALREADY PRESENT NAMES:
class A { ...
class proxy { ...
template<class T> proxy& operator=(const T& rhs) {
it = rhs; return *this; }
...but the above can only work if we already have some value in the map.
class A { ...
A() { map_["pi"] = 3.14; } ...
a["pi"] = 3.1415;
COMPLETE REDISIGN:
class MultiType: public boost::variant<int, double, ...> {
public:
template<class T> operator T() {
switch(which()) {
case 0: return boost::get<int>(*this);
case 1: return boost::get<double>(*this);
...
Now we can use std::map<std::string, MultiType> directly (without class A or any proxy).
template<class T>
T& operator[](const std::string& key) {
return boost::get<T>(map_[key]);
}
There's no way for the compiler to deduce T from a call like a["param"];. You'd need to specify it explicitly
a.operator[]<int>("param");
which I doubt is what you're after, but what do I know.

adding arrays of different types (c++)

i need to dynamically create arrays containing different numerical types, including char, int, unsigned int, float, double. i'd like to be able to create any two of these arrays and, assuming they're of the same length, implement arithmetic operators such as operator+=
i've been able to implement the array as a template, but i don't know how to implement any arithmetic operators, since i can't know what the other array's type will be at compile time, or even when the first array is created (i will know the type for the array i'm constructing). i looked at std::array, but it doesn't support arithmetic operators. another alternative, which is definitely not elegant (but does work), is to implement a series of type specific operators, such as
MyArray<V> operator+ (const MyArray<float>& addend) const;
MyArray<V> operator+ (const MyArray<double>& addend) const;
MyArray<V> operator+ (const MyArray<int32>& addend) const;
MyArray<V> operator+ (const MyArray<int16>& addend) const;
thanks for any advice.
Alright, its probably obvious enough from my comments of everything in this thread that this is a particular sore spot for me. And this is for good reason, I was once like you. I was like, I can overload operators! AMAZING! OVERLOAD ALL THE OPERATORS (this was with a custom image container type). After a while, a few things became clear:
Operators are hard to correctly declare, especially templated ones.
Templated operators cannot have their types set explicitely, only implicitly.
Operation order doesn't make sense all the time.
Operators must either use exceptions as their "fail" mode which is not ideal in all cases, or use "enable-if" type syntax if the fail can be detected at compile time.
Operator MEANING is hard to document/elucidate. Different interpretations of what an operator should "do" makes it hard to figure out. (Should the MyArray<T>+MyArray<J> work as a memberwise plus like T+J or should it work like a concatenate like 'string+string'?)
Operators must return by value, which can cause overhead if your moves aren't all set up correctly/you aren't in C++11/for any reason return value elision doesn't happen.
Overall, writing your own container types is a great way to redo alot of work the STL has already done.
You COULD do it like (at a namespace scope) (assuming you have a templated cast operator available)
template <typename T, typename J>
MyArray<decltype(T()+J())> operator+(const MyArray<T>& x,const MyArray<J>& y)
{
using K=decltype(T()+J());
MyArray<K> ret(x.size());//or something?
for (size_t i = 0; i < x.size(); i++) {ret[i]=x[i]+y[i];}//could replace with foreach
return ret;
};
Though using the following with vectors just makes more sense. You can wrap it in a "add" call if you want.
std::vector<T> a;//or whatever
std::vector<J> b;//or whatever
std::vector<K> c(a.size());//note: you can still use the decl type here, OR just define it to whatever you actually want it to be
std::transform(a.begin(), a.end(). b.begin(), c.begin(), std::plus<K>());
If you are trying to do this all over the place, and are trying to make a matrix math library, use one like Eigen, it'll save you a lot of work, it'll be strongly typed as a matrix and not a generic collection, and it'll be done with the full math knowledge the Eigen team has.
You can use one more template parameter:
template<class V, class T> MyArray<V> operator+ (const MyArray<T>& addend) const;
Then the cast will always be according to your main array type.
You will likely have to dispatch your operations by a result type selected by some type traits.
Simplified for a number (no vector):
#include <iostream>
template <typename T>
struct Number {
T value;
Number(T value) : value(value) {}
template <typename U>
explicit Number(U value) : value(value) {}
operator T () const { return value; }
};
#define C_PLUS_PLUS_11 (201103L <= __cplusplus)
template <typename U, typename V>
struct binary_operation_traits {
#if C_PLUS_PLUS_11
typedef decltype(U() + V()) result_type;
#endif
};
#if ! C_PLUS_PLUS_11
template <typename T>
struct binary_operation_traits<T, T> {
typedef T result_type;
};
template <>
struct binary_operation_traits<int, float> {
typedef float result_type;
};
template <>
struct binary_operation_traits<int, double> {
typedef double result_type;
};
// And so on ...
#endif
template <typename U, typename V>
Number<typename binary_operation_traits<U, V>::result_type>
operator + (const Number<U>& a, const Number<V>& b) {
typedef typename binary_operation_traits<U, V>::result_type result_type;
return Number<result_type>(result_type(a) + result_type(b));
}
int main ()
{
Number<int> a(1);
Number<double> b(1.5);
std::cout << a + b << '\n';
return 0;
}

Why does ostream_iterator need to explicitly declare the type of objects to output?

In current C++, the class ostream_iterator was designed like the following:
// excerpted from the standard C++
template<class T, ...>
class ostream_iterator
{
public:
ostream_iterator(ostream_type&);
...
ostream_iterator<T,...>& operator =(const T&);
...
};
To me, this design is suboptimal. Because the user must specify the type T when declaring an ostream_iterator like this: ostream_iterator<int> oi(cout); In fact, cout can take any type of object as its argument, rather than only one type. This is an obvious restriction.
// Below is my own version
// doesn't need any template parameter here
class ostream_iterator
{
public:
ostream_iterator(ostream_type&);
...
// define a template member function which can take any type of argument and output it
template<class T>
ostream_iterator<T,...>& operator =(const T&);
...
};
Now, we can use it as follows:
ostream_iterator oi(cout);
I think it is more generic and more elegant than
ostream_iterator<int> oi(cout);
Am I right?
The simple answer is that iterator have associated types and ostream_iterator conceptually violates the concept of an iterator by requiring a value_type even when it is not necessary. (This is basically #pts's answer)
What you are proposing is related to the idea behind the new "transparent operators", such as the new std::plus<void>. Which consist in having a special instantiation whose member function has a delayed type deduction.
It is also backward compatible because void is not a useful instantiation to begin with. Moreover the void parameter is also the default. For example template<T = void> struct std::plus{...} is the new declaration.
A possible implementation of a transparent ostream_iterator
Going back of std::ostream_iterator, an important test is whether we want to make it work with std::copy as std::ostream_iterator is usually used:
std::vector<int> v = {...};
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
The technology for a transparent std::ostream_iterator is not there yet, because this fails:
std::copy(v.begin(), v.end(), std::ostream_iterator<void>(std::cout, " "));
To make this work, one can explicitly define the void instance. (This completes #CashCow 's answer)
#include<iterator>
namespace std{
template<>
struct ostream_iterator<void> :
std::iterator<std::output_iterator_tag, void, void, void, void>
{
ostream_iterator(std::ostream& os, std::string delim) :
os_(os), delim_(delim)
{}
std::ostream& os_;
std::string delim_;
template<class T> ostream_iterator& operator=(T const& t){
os_ << t << delim_;
return *this;
}
ostream_iterator& operator*(){return *this;}
ostream_iterator& operator++(){return *this;}
ostream_iterator& operator++(int){return *this;}
};
}
Now this works:
std::copy(v.begin(), v.end(), std::ostream_iterator<void>(std::cout, " "));
Moreover, if we convince the standard committee to have a default void parameter (as they did with with std::plus):
template<class T = void, ...> struct ostream_iterator{...}, we could go a step further and omit the parameter altogether:
std::copy(v.begin(), v.end(), std::ostream_iterator<>(std::cout, " "));
The root of the problem and a possible way out
Finally, in my opinion the problem might also be conceptual, in STL one expects an iterator to have a definite value_type associated even if it is not necessary like here. In some sense ostream_iterator violates some concepts of what is an iterator.
So there are two things that are conceptually wrong in this usage: 1) when one copies one expects to know the type of the source (container value_type) and target types 2) one is not copying anything in the first place!. In my opinion there is a double design mistake in this typical usage. There should be a std::send that works with a template shift << operators directly, instead of making = redirect to << as ostream_iterator does.
std::send(v.begin(), v.end(), std::cout); // hypothetical syntax
std::send(v.begin(), v.end(), std::ostream_receiver(std::cout, " ")); // hypothetical syntax
std::send(v.begin(), v.end(), 'some ostream_filter'); // hypothetical syntax
(The last argument should fulfill some kind of Sink concept).
** Using std::accumulate instead and a possible implementation of
std::send **
From a conceptual point of view, sending objects to a stream is more of an "accumulate" operation than a copy operator, so in principle std::accumulate should be a more suitable candidate, besides we don't need "target" iterators for it.
The problem is that std::accumulate wants to make copies of every object that is being accumulated, so this doesn't work:
std::accumulate(e.begin(), e.end(), std::cout,
[](auto& sink, auto const& e){return sink << e;}
); // error std::cout is not copiable
To make it work we need to do some reference_wrapper magic:
std::accumulate(e.begin(), e.end(), std::ref(std::cout),
[](auto& sink, auto const& e){return std::ref(sink.get() << e);}
);
Finally, the code can be simplified by having the equivalent of std::plus for the shift operator, in modern C++ this should look like this IM:
namespace std{
template<class Sink = void, class T = void>
struct put_to{
std::string delim_;
using sink_type = Sink;
using input_type = T;
Sink& operator()(Sink& s, T const& t) const{
return s << t << delim_;
}
};
template<>
struct put_to<void, void>{
std::string delim_;
template<class Sink, class T>
Sink& operator()(Sink& s, T const& t){
return s << t;
}
template<class Sink, class T>
std::reference_wrapper<Sink> operator()(std::reference_wrapper<Sink> s, T const& t){
return s.get() << t << delim_;
}
};
}
Which can be used as:
std::accumulate(e.begin(), e.end(), std::ref(std::cout), std::put_to<>{", "});
Finally we can define:
namespace std{
template<class InputIterator, class Sink>
Sink& send(InputIterator it1, InputIterator it2, Sink& s, std::string delim = ""){
return std::accumulate(it1, it2, std::ref(s), std::put_to<>{delim});
}
}
Which can be used as
std::send(e.begin(), e.end(), std::cout, ", ");
Finally, there is no dilemma about the type of any output_iterator here.
It appears you could be right.
Let's see if we can construct an ostream_iterator that does not need a template argument.
The iterator works by copying values into it, so *iter = x; ++iter;
The iterator cheats by making operator* return itself and ++iter also returning itself without changing any state. The "magic" is in the operator= which performs the output.
The "cout" must be a class member of type ostream*. It needs to be a pointer as iterators must be assignable, thus we assign the member (call it os) to the address of the stream passed in.
So we would overload operator= this way:
template< typename T >
our_ostream_iterator& operator=( const T& t )
{
(*os) << t;
if( delim )
(*os) << delim;
return *this;
}
Note that the templatised operator= should not oveload operator=(our_ostream_iterator const&) which is more specialised than the template.
You would still want a template on the element type so we will call that our_basic_ostream_iterator
ostream_iterator would still remain a template class on its element type. Thus:
template< typename E, typename TR=char_traits<E> >
class our_basic_ostream_iterator : public std::iterator< /*traits here*/ >
{
public:
typedef E element_type;
typedef TR traits_type;
typedef basic_ostream< E, TR > stream_type;
private:
stream_type * os;
const E* delim;
public:
our_basic_ostream_iterator( stream_type s, const E* d = nullptr ) :
os( &s ), delim( d )
{
}
our_basic_ostream_iterator& operator++() { return *this; }
our_basic_ostream_iterator operator++(int) { return *this; }
our_basic_ostream_iterator& operator*() { return *this; }
template< typename T >
our_basic_ostream_iterator& operator=( const T& t ); // as above
};
and then of course
typedef our_basic_ostream_iterator<char> our_ostream_iterator;
typedef our_basic_ostream_iterator<wchar_t> our_wostream_iterator;
The drawback of all of this though is that the above does not conform to all the properties of iterators such that it could be passed to any algorithm / class that requires a forward iterator. Why? Because such an algorithm should be able to invoke iterator_traits to extract the element type and the class above does not contain an element type.
It would lead to compile-time errors in the algorithm that is using your iterator and would potentially be hard to track down the reason why.
I think the reason is that it has other members also. Obviously the entire set of member functions need to be consistent in their behavior for a given set of T and other template arguments.
There's danger in operator < being instantiated for a set of template arguments which is different from what is used to instantiate operator * or operator++
Hence, the individual methods are not template themselves and rather the entire class is a template so ensure uniform T and other template arguments.
Yes, you are right. It would be more flexible as you suggest. However, the way it's designed fits more closely to how STL uses iterators: one iterator type for data type (T).

Creating a template predicate class requiring a pointer to method function, and ensuing compiler errors

I'm building a series of predicates that duplicate lots of code, and so are being changed into a single template function class based on the std::unary_function. The idea is that my class interface requires methods such as Element_t Element() and std::string Name() to be defined, so the predicate template arguments are the object type and a value type to which comparison will be made as follows:
// generic predicate for comparing an attribute of object pointers to a specified test value
template <class U, typename R>
class mem_fun_eq : public std::unary_function <U*, bool> {
private:
typedef R (U::*fn_t)();
fn_t fn;
R val;
public:
explicit mem_fun_eq (fn_t f, R& r) : fn(f), val(r) { }
bool operator() (U * u) const {
return (u->*fn)() == val;
}
};
Thus, if I have:
class Atom {
public:
const Element_t& Element() const { return _element; }
const std::string& Name() const { return _name; }
};
I would like to perform a search on a container of Atoms and check for either the Name or Element equality using my template predicate like so:
typedef std::string (Atom::*fn)() const;
Atom_it it = std::find_if( _atoms.begin(), _atoms.end(), mem_fun_eq <Atom, std::string> ((fn)&Atom::Name, atomname));
but compiling this returns the following error on the std::find_if line:
error: address of overloaded function with no contextual type information
Also, trying to form the same predicate for a check of the Element() as such:
typedef Atom::Element_t& (Atom::*fn)() const;
Atom_it it = std::find_if(_atoms.begin(), _atoms.end(), mem_fun_eq <Atom, Atom::Element_t> ((fn)&Atom::Element, elmt);
creates a different error!
error: no matching function for call to ‘mem_fun_eq<Atom, Atom::Element_t>::mem_fun_eq(Atom::Element_t& (Atom::*)()const, const Atom::Element_t&)’
note: candidates are: mem_fun_eq<U, R>::mem_fun_eq(R (U::*)(), R&) [with U = Atom, R = Atom::Element_t]
note: mem_fun_eq<Atom, Atom::Element_t>::mem_fun_eq(const mem_fun_eq<Atom, Atom::Element_t>&)
Firstly, am I reinventing the wheel with this predicate? Is there something in the STL that I've missed that does the same job in a single class? I can always break the predicate down into several more specific ones, but I'm trying to avoid that.
Secondly, can you help me with the compiler errors?
I don't know of any easy way to do this using the bits provided with the STL. There is probably some clever boost way, using iterator adapters, or boost::lambda, but personally I wouldn't go that way.
Obviously C++0x lambdas will make all this easy.
Your problem is attempting to cast a function like this:
const std::string&(Atom::*)()
into a function like this:
std::string (Atom::*)()
If you replace your typedef R (U::*fn_t)(); with typedef const R& (U::*fn_t)() const; then it should work.
The following avoids this problem and also provides type inference so that you can just write mem_fun_eq(&Atom::Name, atomname). It compiles for me, although I haven't tested it.
template<typename U, typename R, typename S>
class mem_fun_eq_t : public std::unary_function<U const*, bool>
{
private:
R (U::*fn_)() const;
S val_;
public:
mem_fun_eq_t(R (U::*fn )() const, S val) : fn_(fn), val_(val){}
bool operator()(U * u)
{
return (u->*fn_)() == val_;
}
};
template<typename U, typename R, typename S>
mem_fun_eq_t<U, R, S> mem_fun_eq(R (U::*fn)() const, S val)
{
return mem_fun_eq_t<U, R, S>(fn, val);
}
Have you thought of trying to mix in a mem_fun_ref or mem_fun object in place of the member function call?
Basically, you call on mem_fun to create an object that accepts two arguments T* and a template argument to the function A if it has one (or void if it doesn't). Hence you combine it like so:
template<typename MemFunc, typename CompareType, typename T>
struct MyPredicate{
MyPredicate(MemFunc _functionObj, CompareType _value)
: m_Value(_value),
m_Function(_functionObj){}
bool operator()(const T &_input){
return m_Value == m_Function(_input);
}
private:
MemFunc m_Function;
CompareType m_Value;
};
Edit:
Ok, that's not completely working so why not have:
struct NamePred: binary_function<Atom*,string,bool>{
bool operator()(Atom *_obj, string _val){
return _obj->Name() == _val;
};
};
then use bind2nd
find_if( atoms.begin(), atoms.end(), bind2nd( NamePred, "yo" ) );