generic lookup method? - c++

I'd like a generic method for retrieving the data from a vector.
I have a the following class and vector:
class myClass
{
public:
myClass(int myX, float myZ, std::string myFoo)
: x ( myX )
, z ( myZ )
, foo ( myFoo )
{
}
myClass()
{
}
int x;
float z;
std::string foo;
} ;
std::vector < myClass > myVector;
(The complete code can be seen here: http://codepad.org/iDD1Wme5 )
In this example I would like to be able to retrieve objects in the vector based on the "z" or "foo" members without having to write another 2 functions similar to "FindDataById".
Is that possible?

You can use a template and pointer to member.
typedef vector<myClass> myVector;
template<typename T>
bool FindDataById(const T &id, T myClass::* idMember, myClass &theClass,
const myVector &theVector)
{
for(myVector::const_iterator itr = theVector.begin(); itr != myVector.end();
++itr){
if((*itr).*idMember == id){
theClass = *itr;
return true;
}
return false;
}
Then call using, e.g.,
FindDataById(string("name"), &myClass::foo, theClass, theVector)
FindDataById(5, &myClass::x, theClass, theVector)
FindDataById(5.25f, &myClass::z, theClass, theVector)
Or, go with the find_if idea:
template<typename T>
struct Finder {
T val_;
T myClass::* idMember_;
Finder(T val, T myClass::* idMember) : val_(val), idMember_(idMember) {}
bool operator()(const myClass &obj) { return obj.*idMember_ == val_; }
};
And use:
find_if(theVector.begin(), theVector.end(), Finder<string>("name", &myClass::foo))
find_if(theVector.begin(), theVector.end(), Finder<int>(5, &myClass::x))
find_if(theVector.begin(), theVector.end(), Finder<float>(3.25f, &myClass::z))
See the answer of MSalters for a way to deduce the template argument automatically.

std::find_if has already been suggested, but without a code sample, so here's a more detailed version:
Define two functors to identify the object you're interested in:
struct z_equals {
z_equals(float z) : z(z) {}
bool operator()(const myClass& obj)
return z == obj.z;
}
float z;
};
struct foo_equals {
foo_equals(const std::string& foo) : foo(foo) {}
bool operator()(const myClass& obj)
return foo == obj.foo;
}
const std::string& foo;
};
And now, to search for elements where z == 42.0f, or foo == "hello world":
std::find_if(myVector.begin(), myVector.end(), z_equals(42.0f));
std::find_if(myVector.begin(), myVector.end(), foo_equals("hello world"));

You can use functors and pass it to your lookup method. That I mean is, define class which will overload bool operator( vectorElement element) and within this operator you will choose method how do you want to lookup the values.
template <typename T>
class ILookUp
{
bool operator( vector<T> elem)
{
if (elem == something)
return true;
false;
}
};
class VectorStorage
{
std::vector<Elements> lookup( ILookUp<Elements> lookup)
{
.....
if ( lookup(elem))
{
//add element to vector or whatever.
}
.....
return result;
}
.....
}

It might be worth taking a look at std::find defined in algorithm and boost::lambda

Without lambda's you'd need to write some predicates, or at least instantiate them:
template
struct member_select : public std::unary_function
{
T t;
T U::* m_u;
member_select(T const& t, T U::* m_u) : t(t), m_u(m_u) {}
bool operator()(U const& u) const { return u.*m_u == t; }
};
template
member_select make_member_select(T const& t, T U::* m_u)
{
return member_select(t, m_u);
}
Use: std::find_if(..., make_member_select("x", &myClass::foo));

Related

Using class member variable as reference

I would like to have a class member variable to be able to switch in between items in a map so that when it is modified, the content of the map is also modified.
Is there any way other than to use a pointer to the content of the map ? Old code only needed only variable, now the new one needs to switch. If I change the variable type, then all functions using this member variable need to be changed. Not complicated, but I would find it ugly to have * in front of it everywhere...
A reference variable cannot be rebound, so how can I achieve this ?
class A
{
std::map<std::string,std::vector<int>> mMyMap;
std::vector<int>& mCurrentVector;
std::vector<int>* mCurrentVectorPointer;
std::vector<int> mDefaultVector;
void setCurrentVector(int iKey);
void addToCurrentVector(int iValue);
}
A::A():
mDefaultVector(std::vector<int>())
mCurrentVector(mDefaultVector)
{
mMyMap["key1"] = std::vector<int>(1,1);
mMyMap["key2"] = std::vector<int>(1,2);
mCurrentVectorPointer = &mMyMap[0];
}
A::setCurrentVector(std::string iKey)
{
if(mMyMap.find(iKey) != mMyMap.end())
{
mCurrentVector = mMyMap[iKey]; //can't change a reference...
mCurrentVectorPointer = &mMyMap[iKey]; //could use pointer, but
}
}
A::addToCurrentVector(int iValue)
{
mCurrentVector.push_back(iValue);
//or
(*mCurrentVectorPointer).push_back(iValue);
//
mCurrentVectorPointer->push_back(iValue);
}
void main()
{
A wClassA();
wClassA.setCurrentVector("key2");
wClassA.addToCurrentVector(3);
wClassA.setCurrentVector("key1");
wClassA.addToCurrentVector(4);
}
mMyMap["key1"] now contains 1,4
mMyMap["key2"] now contains 2,3
You can't reseat a reference once it has been assigned which means you are left with using your other option, a pointer.
As I understand it, you're refactoring some existing code which only used a single vector, whereas now you need a map of vectors.
You're trying to achieve this with minimal modifications, and keeping the interface to the vector the same.
An option would be to use a local reference, assigned from your pointer.
class A
{
using Vector = std::vector<int>;
public:
A()
{
map_["key1"] = std::vector<int>(1,1);
map_["key2"] = std::vector<int>(1,2);
curr_vec_ = &map_["key1"];
}
void setCurrentVector(const std::string& key)
{
if(map_.find(key) != map_.end())
{
curr_vec_ = &map_[key];
}
}
void addToCurrentVector(int val)
{
assert(curr_vec_);
Vector& curr_vec = *curr_vec_; // local reference
curr_vec.push_back(val);
curr_vec[0] = 2;
// etc
}
private:
std::map<std::string, Vector> map_;
Vector* curr_vec_ = nullptr;
}
You may write some wrapper:
#define Return(X) noexcept(noexcept(X)) -> decltype(X) { return X; }
template <typename U>
class MyVectorRef
{
private:
std::vector<U>* vec = nullptr;
public:
explicit MyVectorRef(std::vector<U>& v) : vec(&v) {}
void reset(std::vector<U>& v) {vec = &v;}
// vector interface
auto at(std::size_t i) const Return(vec->at(i))
auto at(std::size_t i) Return(vec->at(i))
auto operator [](std::size_t i) const Return(vec->operator[](i))
auto operator [](std::size_t i) Return(vec->operator[](i))
template <typename ... Ts> auto assign(Ts&&... ts) Return(vec->assign(std::forward<Ts>(ts)...))
auto assign( std::initializer_list<U> ilist ) Return(vec->assign(ilist))
template <typename T> auto push_back(T&& t) const Return(vec->push_back(std::forward<T>(t)))
template <typename T> auto emplace_back(T&& t) const Return(vec->emplace_back(std::forward<T>(t)))
auto begin() const Return(vec->begin())
auto begin() Return(vec->begin())
auto end() const Return(vec->end())
auto end() Return(vec->end())
auto cbegin() const Return(vec->cbegin())
auto cend() const Return(vec->cend())
// ...
};
and then, use it:
class A
{
public:
A() : mCurrentVector(mDefaultVector) {
mMyMap["key1"] = std::vector<int>(1,1);
mMyMap["key2"] = std::vector<int>(1,2);
}
std::map<std::string, std::vector<int>> mMyMap;
std::vector<int> mDefaultVector;
MyVectorRef<int> mCurrentVector;
void setCurrentVector(std::string iKey)
{
auto it = mMyMap.find(iKey);
if (it != mMyMap.end())
{
mCurrentVector.reset(it->second);
}
}
void addToCurrentVector(int iValue)
{
mCurrentVector.push_back(iValue);
}
};
But I think it would be simpler to just create a getter in A and use directly a pointer:
class A
{
public:
A() : mCurrentVector(&mDefaultVector) {
mMyMap["key1"] = std::vector<int>(1,1);
mMyMap["key2"] = std::vector<int>(1,2);
}
std::map<std::string, std::vector<int>> mMyMap;
std::vector<int> mDefaultVector;
std::vector<int>* mCurrentVector;
std::vector<int>& GeCurrentVector() { return *mCurrentVector; }
void setCurrentVector(std::string iKey)
{
auto it = mMyMap.find(iKey);
if (it != mMyMap.end())
{
mCurrentVector = &it->second;
}
}
void addToCurrentVector(int iValue)
{
GeCurrentVector().push_back(iValue);
}
};

How to allow range-for loop on my class? [duplicate]

This question already has answers here:
How to make my custom type to work with "range-based for loops"?
(10 answers)
Closed 7 years ago.
I have a class like this:
class Foo {
private:
int a,b,c,d;
char bar;
double m,n
public:
//constructors here
};
I wanna allow range-for loop on my class, e.g.
Foo foo {/*...*/};
for(auto& f : foo) {
//f will be a specific order such as c,b,d,(int)m,(int)bar,a,(int)n
}
How can I achieve this? I was looking at iterator but don't know what are the requirements for a range-for loop. (Please don't ask me to use array or STL type)
The loop is defined to be equivalent to:
for ( auto __begin = <begin-expr>,
__end = <end-expr>;
__begin != __end;
++__begin ) {
auto& f = *__begin;
// loop body
}
where <begin-expr> is foo.begin(), or begin(foo) if there isn't a suitable member function, and likewise for <end-expr>. (This is a simplification of the specification in C++11 6.5.4, for this particular case where the range is a lvalue of class type).
So you need to define an iterator type that supports pre-increment ++it, dereference *it and comparison i1 != i2; and either
give foo public member functions begin() and end(); or
define non-member functions begin(foo) and end(foo), in the same namespace as foo so that they can be found by argument-dependent lookup.
This seems fairly un-C++-like, and rather prone to breakage. What if the iteration order is changed (accidentally or not) during some update in the future? Clients relying on a specific order will break.
All that said if you wish to support this all you have to do is implement your own iterator and provide begin/end methods (or free functions with those names) to provide access. Then the iterator takes care of remembering which attribute it's currently looking at and provides it when dereferenced.
Here is a basic framework I came up with:
#include <iterator>
struct Foo;
template<typename Type>
struct MemberPtrBase {
virtual ~MemberPtrBase() { }
virtual Type get() const = 0;
virtual MemberPtrBase & set(Type const &) = 0;
};
template<typename Class, typename RealType, typename CommonType>
struct MemberPtr : MemberPtrBase<CommonType> {
public:
MemberPtr(Class * object, RealType(Class::*member))
: m_object(object), m_ptr(member)
{ }
CommonType get() const {
return m_object->*m_ptr;
}
MemberPtr & set(CommonType const & val) {
m_object->*m_ptr = val;
return *this;
}
MemberPtr & operator=(RealType const & val) {
return set(val);
}
operator CommonType() const {
return get();
}
private:
Class * m_object;
RealType (Class::*m_ptr);
};
template<typename Class, typename... Types>
struct MemberIterator {
public:
using CommonType = typename std::common_type<Types...>::type;
public:
MemberIterator(Class & obj, std::size_t idx, Types(Class::*...member))
: m_object(obj), m_index(idx), m_members { new MemberPtr<Class, Types, CommonType>(&obj, member)... }
{ }
MemberPtrBase<CommonType> & operator*() const {
return *m_members[m_index];
}
bool operator==(MemberIterator const & it) const {
return (&m_object == &it.m_object) && (m_index == it.m_index);
}
bool operator!=(MemberIterator const & it) const {
return (&m_object != &it.m_object) || (m_index != it.m_index);
}
MemberIterator & operator++() {
++m_index;
return *this;
}
private:
Class & m_object;
std::size_t m_index;
MemberPtrBase<CommonType> * m_members[sizeof...(Types)];
};
struct Foo {
public:
using iterator = MemberIterator<Foo, int, int, int, int>;
public:
Foo(int a, int b, int c, int d)
: m_a(a), m_b(b), m_c(c), m_d(d)
{ }
iterator begin() {
return iterator(*this, 0, &Foo::m_b, &Foo::m_d, &Foo::m_c, &Foo::m_a);
}
iterator end() {
return iterator(*this, 4, &Foo::m_b, &Foo::m_d, &Foo::m_c, &Foo::m_a);
}
private:
int m_a, m_b, m_c, m_d;
};
If you have a basic understanding of variadic templates, I think the code is self-explanatory.
Usage is simple:
#include <iostream>
int main(int argc, char ** argv) {
Foo foo { 1, 2, 3, 4 };
for(auto & mem : foo) {
std::cout << mem.get() << std::endl;
mem.set(3);
}
for(auto & mem : foo) {
std::cout << mem.get() << std::endl;
}
}
A POC can be found on ideone

Passing a functor as C++ template parameter

As an exercise for my personal enlightenment, I implement vector math with expression templates. I want to implement some operations that apply the same unary function to all elements to a vector expression. So far, I do this.
My base vector expression template is implemented like this
template <typename E>
class VectorExpr {
public:
int size() const { return static_cast<E const&>(*this).size(); }
float operator[](int i) const { return static_cast<E const&>(*this)[i]; }
operator E& () { return static_cast<E&>(*this); }
operator E const& () const { return static_cast<const E&>(*this); }
}; // class VectorExpr
Then, an object supposed to be a vector will look like this
class Vector2 : public VectorExpr<Vector2> {
public:
inline size_t size() const { return 2; }
template <typename E>
inline Vector2(VectorExpr<E> const& inExpr) {
E const& u = inExpr;
for(int i = 0; i < size(); ++i)
mTuple[i] = u[i];
}
private:
float mTuple[2];
};
Let's say I want to apply std::sin to all elements of an expression
template <typename E>
class VectorSin : public VectorExpr<VectorSin<E> > {
E const& mV;
public:
VectorSin(VectorExpr<E> const& inV) : mV(inV) {}
int size() const { return mV.size(); }
float operator [] (int i) const { return std::sin(mV[i]); }
};
Question => If I want to add more functions, I copy-paste what I do for the sin function, for every single function (like cos, sqrt, fabs, and so on). How I can avoid this kind of copy-pasting ? I tried things and figured out I'm still low in template-fu. No boost allowed ^^
template <typename F, typename E>
class VectorFunc : public VectorExpr<VectorFunc<F, E> > {
E const& mV;
public:
VectorSin(VectorExpr<E> const& inV) : mV(inV) {}
int size() const { return mV.size(); }
float operator [] (int i) const { return f(mV[i]); }
// this assumes the Functor f is default constructible, this is
// already not true for &std::sin. Adding the constructor that
// takes f, is left as an exercise ;)
F f;
};
In addition to the answer by pmr, The standard <cmath> functions aren't functors, so you couldn't use them directly to specify unique specialisations of your class - i.e. you wouldn't have a separate template instantiation for std::sin versus std::cos (which is what I gather you're aiming for? correct me if I've misunderstood you on that).
You could create a wrapper in order to map a function pointer to a distinct type, e.g.
#include <iostream>
template< void (*FuncPtr)() > struct Func2Type
{
void operator() () { FuncPtr(); }
};
void Hello() { std::cout << "Hello" << std::endl; }
void World() { std::cout << "world" << std::endl; }
int main()
{
Func2Type<Hello> test1;
Func2Type<World> test2;
test1();
test2();
}
That way you could use them as template arguments in the same way as a normal functor class

Can I write a C++ functor that accepts both a raw pointer and a smart pointer?

Given the following:
struct Foo
{
int bar() const;
};
struct IsEqual : public std::unary_function<Foo*, bool>
{
int val;
IsEqual(int v) : val(v) {}
bool operator()(const Foo* elem) const
{
return elem->bar() == val;
}
};
I have a container of Foo* and I use std::find_if and std::not1 to find out if there are any elements in the container where bar() returns something different from a given value. The code looks like this:
// Are all elements equal to '2'?
bool isAllEqual(const std::vector<Foo*> &vec)
{
return find_if(vec.begin(), vec.end(), std::not1(IsEqual(2))) == vec.end();
}
Fast-forward into the future and I now have a different container, this time containing std::tr1::shared_ptr<Foo>. I'd love to simply re-use my functor in an overloaded version of isAllEqual(). But I can't. Foo* and shared_ptr<Foo> are different types. And I need to inherit from unary_function so I can use not1. It'd be more elegant if I could avoid writing the same functor twice.
Questions:
Is there any way to write IsEqual so it can use both raw and smart pointers?
Did I handcuff myself by using std::not1? Should I just write IsNotEqual instead?
Restrictions:
I can't use anything from the boost library.
Our compiler isn't cool enough to support C++0x lambdas.
How about:
template<typename T>
struct IsEqual : public std::unary_function<const T&, bool>
{
int val;
IsEqual(int v) : val(v) {}
bool operator()(const T& elem) const
{
return elem->bar() == val;
}
};
template<typename T>
IsEqual<T> DeduceEqualityComparer(int v, T) { return IsEqual<T>(v); }
// Are all elements equal to '2'?
template<typename TContainer>
bool isAllEqual(const TContainer& coll)
{
using std::begin; // in C++0x, or else write this really simple function yourself
using std::end;
if (begin(coll) == end(coll)) return true;
return find_if(begin(coll), end(coll), std::not1(DeduceEqualityComparer(2, *begin(coll)))) == end(coll);
}
// --*-- C++ --*--
#include <vector>
#include <algorithm>
#include <iostream>
// Template unary function example.
template <typename T>
struct IsEqual : public std::unary_function<T, bool>
{
int v;
IsEqual (int v) : v (v) {}
bool operator () (const T & elem) const
{
return elem ? elem->bar () == v : false;
}
};
// Generic algorithm implementation example...
template <typename T1, typename T2>
bool isAllEqual (const T1 & c, T2 v)
{
return find_if (
c.begin (), c.end (),
std::not1 (IsEqual <typename T1::value_type> (v))) == c.end ();
}
// Some arbitrary pointer wrapper implementation,
// provided just for an example, not to include any
// specific smart pointer implementation.
template <typename T>
class WrappedPtr
{
const T *v;
public:
typedef void (WrappedPtr<T>::*unspecified_boolean_type) () const;
WrappedPtr (const T *v) : v (v) {}
const T *operator -> () const { return v; }
operator unspecified_boolean_type () const
{
return v != NULL ?
&WrappedPtr<T>::unspecified_boolean_true : NULL;
}
private:
void unspecified_boolean_true () const {}
};
// Example of structure that could be used with our algorithm.
struct Foo
{
int v;
Foo (int v) : v (v) {}
int bar () const
{
return v;
}
};
// Usage examples...
int main ()
{
Foo f1 (2), f2 (2);
// Example of using raw pointers...
{
std::vector<Foo *> vec;
vec.push_back (NULL);
vec.push_back (&f1);
vec.push_back (&f2);
if (isAllEqual (vec, 2))
std::cout << "All equal to 2" << std::endl;
else
std::cout << "Not all equal to 2" << std::endl;
}
// Example of using smart pointers...
{
std::vector< WrappedPtr<Foo> > vec;
vec.push_back (NULL);
vec.push_back (&f1);
vec.push_back (&f2);
if (isAllEqual (vec, 2))
std::cout << "All equal to 2" << std::endl;
else
std::cout << "Not all equal to 2" << std::endl;
}
}
My shot would be something like this:
template<typename PtrToFoo>
struct IsEqual : public std::unary_function<PtrToFoo, bool>
{
int val;
IsEqual(int v) : val(v) {}
bool operator()(PtrToFoo elem) const
{
return elem->bar() == val;
}
};
You'll have a different operator() instantiation for everything dereferencable with ->, so raw pointers and smart pointers.
You could maybe do something tricky with implicit conversions:
class IsEqualArg {
public:
// Implicit conversion constructors!
IsEqualArg(Foo* foo) : ptr(foo) {}
IsEqualArg(const std::tr1::shared_ptr<Foo>& foo) : ptr(&*foo) {}
private:
Foo* ptr;
friend struct IsEqual;
};
struct IsEqualArg : public std::unary_function<IsEqualArg, bool> {
bool operator()( const IsEqualArg& arg ) const;
//...
};
But I'd really rather just write a IsNotEqual.
Ben's answer is really the only thing you can do in c++03. In C++0x though, and/or with boost::bind, you don't need to inherit from unary_function. This allows you to use a templated () operator. You can usually get away with the same in C++03 but I think that it's technically incorrect to do so.

find int inside struct with find_if for std::list with structs

How can I use find_if with a std::list if the list contains structs? My first pseudo code attempt at this looks like this:
typename std::list<Event>::iterator found =
find_if(cal.begin(), cal.last(), predicate);
The problem here is that the predicate is not directly visible in the list but inside event.object.return_number(). How am I suppose to refer to an int that is nested inside the struct and needs a get method to be accessed.
You can use a functor class (which is like a function, but allows you to have state, such as configuration):
class Predicate
{
public:
Predicate(int x) : x(x) {}
bool operator() (const Cal &cal) const { return cal.getter() == x; }
private:
const int x;
};
std::find_if(cal.begin(), cal.end(), Predicate(x));
In C++0x, which your compiler probably already partially implements, you can do the following:
find_if(cal.begin(), cal.last(), [&](const Event& e)
{
return e.object.return_number() == value_to_find;
});
You set up your predicate something like this:
struct IsEventObjectReturnNumber
{
int num;
explicit IsEventObjectReturnNumber( int n ) : num( n ) {}
bool operator()(const Event & event ) const
{
return event.object.return_number() == num;
}
};
std::list<Event>::iterator = std::find_if(cal.begin(), cal.end(), IsEventObjectReturnNumber(x));
The (not so simple, but) simplest way (in the absence of C++11) is a custom comparator:
struct CompareMyStruct {
int n_;
CompareMyStruct(int n) : n_(n) { }
bool operator()(const Event& a) const {
return a.object.return_number() == n_;
}
};
typename std::list<Event>::iterator found =
find_if(cal.begin(), cal.last(), CompareMyStruct(123));