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);
}
};
Related
I'm having a hard time calling hash_value.
From this post, I want to apply to vector<vector<E>> where E is a custom object.
My codes as follows:
struct E;
class myclass {
private:
vector<E> lhs;
public:
myclass(const vector<E>& v) :lhs{ v } { };
static size_t hash_value(const vector<E>& v) {
size_t seed = 0;
boost::hash_combine(seed, d.name);
boost::hash_combine(seed, d.scope);
return seed;
}
bool operator==(const vector<E> >& rhs) {
for (unsigned i = 0; i < lhs.size(); i++)
if (lhs[i].name != rhs[i].name || lhs[i].scope!= rhs[i].scope)
return false;
return true;
};
};
then i call this code:
void test(std::vector<std::vector<E>>& A)
{
boost::unordered_set < myclass > input_records(A.size());
for (BOOST_AUTO(it, A.begin()); it != (A.end());) {
auto k = input_records.insert(myclass{*it}); <<--
....
}
}
however i get an error:
Also, in some cases this code executes but hash_value is never called.
I'm not sure what am I missing?
How do I fix this?
You are trying to use boost::unordered_set<myclass>, which will internally use boost::hash<myclass>, which will look for a hash_value(myclass) function in the same namespace as myclass via Argument-Dependent Lookup. You made your hash_value() be a non-static member of myclass, so boost::hash will not be able to find it. But even if it could, it expects your hash_value() to take a single myclass object as a parameter, not a vector.
See Extending boost::hash for a custom data type in Boost's documentation.
Also, a class's operator== compares *this to another object. Inside of myclass, your operator== should take a single myclass object as a parameter, not a vector.
Try this instead:
struct E {
string name;
int scope;
};
size_t hash_value(const E& obj) {
std::size_t seed = 0;
boost::hash_combine(seed, obj.name);
boost::hash_combine(seed, obj.scope);
return seed;
}
class myclass {
private:
vector<E> vec;
public:
myclass(const vector<E>& v) : vec(v) {}
bool operator==(const myclass& rhs) const {
// vector has its own operator== for comparing elements in its array...
return vec == rhs.vec;
}
friend size_t hash_value(const myclass& obj) {
return boost::hash_range(obj.vec.begin(), obj.vec.end());
}
};
void test(std::vector<std::vector<E>>& A)
{
boost::unordered_set<myclass> input_records(A.size());
for (BOOST_AUTO(it, A.begin()); it != (A.end());) {
auto k = input_records.insert(*it);
...
}
}
This one does not work. I wanted to reuse the template that I made for regular pointer. How can I use the same template for std::shared_ptr
class Base
{
public:
int getVal() { return 0; }
};
template <class Type>
bool writeRecordForSet(std::vector<Type> entityPtr)
{
if (entityPtr.size() == 0) return true;
//...
for (auto iter = entityPtr.begin(); iter != entityPtr.end(); iter++) {
Type enPtr = *iter;
int myval = enPtr->getVal();
}
return true;
}
int main()
{
std::vector<std::shared_ptr<Base>> vec_shared;
std::vector<int*> vec_intp;
std::vector<std::unique_ptr<Base>> vec_unique_ptr;
writeRecordForSet(vec_shared);
writeRecordForSet(vec_intp);
writeRecordForSet(vec_unique_ptr);
}
You cannot copy a std::unique_ptr<>, nor a std::vector<std::unique_ptr<>>, so don't try that, but take the argument by reference (which you should to anyway; also use a range-based for loop for clarity)
template <class Type>
bool writeRecordForSet(std::vector<Type> const&entityPtr)
{
if (entityPtr.size() == 0) return true;
for(const auto&enPtr : entityPtr) {
auto myval = enPtr->getVal();
/* ... */
}
return true;
}
Of course, this will fail to compile if called for a Type that does not allow for Type::getVal() (such as your vector<int*> example). If you want your function to work for Types that don't have such a getter, you can use a getter adaptation, i.e.
template<typename T>
inline auto getVal(T const&x) { return T::getVal(); }
inline int getVal(int*x) { return *x; }
Problem 1
bool writeRecordForSet(std::vector<Type> entityPtr) { ... }
is a problem when the argument is of type std::unique_ptr since they cannot be copy constructed.
Change that to use a reference:
bool writeRecordForSet(std::vector<Type>& entityPtr) { ... }
or
bool writeRecordForSet(std::vector<Type> const& entityPtr) { ... }
Problem 2
In the function, you are assuming that the core object is of type Base.
for (auto iter = entityPtr.begin(); iter != entityPtr.end(); iter++) {
Type enPtr = *iter;
// Assuming that enPtr is a Base*, or shared_ptr<Base>, or unique_ptr<Base>
int myval = enPtr->getVal();
}
If you use
std::vector<Base*> vec_intp;
instead of
std::vector<int*> vec_intp;
it will work.
You can add getVal adaptor function to make it work and then write multiple overloads for your int*, shared_ptr<Base>, unique_ptr<Base>.
For example, getVal for int* could be as simple as:
int getVal(int*& p)
{
return *p;
}
And then your writeRecordForSet should call getVal to get int value.
Full example:
#include <vector>
#include <memory>
using namespace std;
class Base
{
public:
int getVal() { return 0; }
};
int getVal(shared_ptr<Base>& p)
{
return p->getVal();
}
int getVal(unique_ptr<Base>& p)
{
return p->getVal();
}
int getVal(int*& p)
{
return *p;
}
template <class Type>
bool writeRecordForSet(std::vector<Type>& entityPtr)
{
if (entityPtr.size() == 0)
return true;
//...
for (auto iter = entityPtr.begin(); iter != entityPtr.end(); iter++) {
int myval = getVal(*iter);
}
return true;
}
int main()
{
std::vector<std::shared_ptr<Base>> vec_shared;
std::vector<int*> vec_intp;
std::vector<std::unique_ptr<Base>> vec_unique_ptr;
writeRecordForSet(vec_shared);
writeRecordForSet(vec_intp);
writeRecordForSet(vec_unique_ptr);
}
I've got this Map in my Entity-Component-System:
std::map<u_int32_t, std::vector<std::shared_ptr<Component>>> _componentMap;
The u_int32_t is the key to a vector of components. There can be multiple instances of the same component. (That's why there's a vector).
Now I would like to have a templated getter-function that returns a Vector of an inherited type:
template<class T> inline const std::vector<std::shared_ptr<T>> & getVector() const
{
u_int32_t key = getKey<T>();
return static_cast<std::vector<std::shared_ptr<T>>>(_componentMap.count(key) ? _componentMap.at(key) : _emptyComponentVec);
}
I know that this doesn't work, since std::vectors of different types are completely unrelated and I cannot cast between them. I would also like to avoid allocating a new vector every time this function is called.
But how I can I get the desired behaviour? When the the components are added I can create an std::vector of the desired derived type.
The question could also be: How can I have an std::map containing different types of std::vector?
For any solutions I can not link against boost, though if absolutely needed, I could integrate single headers of boost.
template<class It>
struct range_view {
It b, e;
It begin() const { return b; }
It end() const { return e; }
using reference = decltype(*std::declval<It const&>());
reference operator[](std::size_t n) const
{
return b[n];
}
bool empty() const { return begin()==end(); }
std::size_t size() const { return end()-begin(); }
reference front() const {
return *begin();
}
reference back() const {
return *std::prev(end());
}
template<class O>
range_view( O&& o ):
b(std::begin(o)), e(std::end(o))
{}
};
this is a quick range view. It can be improved.
Now all you need to do is write a pseudo-random-access iterator that converts its arguments. So it takes a random access iterator over a type T, then does some operation F to return a type U. It forwards all other operations.
The map then stores std::vector<std::shared_ptr<Base>>. The gettor returns a range_view< converting_iterator<spBase2spDerived> >.
Here is a crude implementation of a solution I have in mind for this problem. Of course, there are many rooms to refine the code, but hopefully it conveys my idea.
#include <iostream>
#include <map>
#include <vector>
#include <memory>
using namespace std;
class Base {
public:
virtual void f() const = 0;
};
class A : public Base {
public:
static const int type = 0;
explicit A(int a) : a_(a) {}
void f() const { cout << "calling A::f" << endl;}
int a_;
};
class B : public Base {
public:
static const int type = 1;
explicit B(int a) : a_(a) {}
void f() const { cout << "calling B::f" << endl;}
int a_;
};
class MapWrapper {
public:
template<class T>
void append(int a, vector<T> const& vec) {
types_[a] = T::type;
my_map_[a] = make_shared<vector<T>>(vec);
}
template<class T>
vector<T> const& get(int a) const {
return *static_pointer_cast<vector<T>>( my_map_.at(a) );
}
map<int, shared_ptr<void>> const& get_my_map() const {
return my_map_;
}
vector<shared_ptr<Base>> get_base(int a) const {
vector<shared_ptr<Base>> ret;
switch(types_.at(a)) {
case 0: {
auto const vec = get<A>(a);
for(auto v : vec)
ret.push_back(make_shared<A>(v));
break;
}
case 1: {
auto const vec = get<B>(a);
for(auto v : vec)
ret.push_back(make_shared<B>(v));
break;
}
}
return ret;
}
map<int, shared_ptr<void>> my_map_;
map<int, int> types_;
};
int main() {
MapWrapper map_wrapper;
map_wrapper.append(10, vector<A>{A(2), A(4)});
map_wrapper.append(20, vector<B>{B(5), B(7), B(9)});
for(auto const& w : map_wrapper.get_my_map())
for(auto v : map_wrapper.get_base(w.first))
v->f();
for(auto const& x: map_wrapper.get<A>(10))
cout << x.a_ << " ";
cout << endl;
for(auto const& x: map_wrapper.get<B>(20))
cout << x.a_ << " ";
return 0;
}
The solution was to use reinterpret_cast:
template<class T> inline std::vector<std::shared_ptr<T>> * getVector() const
{
auto key = getKey<T>();
return reinterpret_cast<std::vector<std::shared_ptr<T>> *>( (_componentMap.count(key) ? _componentMap.at(key).get() : const_cast<std::vector<std::shared_ptr<Component>> *>(&_emptyComponentSharedPtrVec)) );
}
It's not very pretty but it does work fine and it fulfills all requirements.
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
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));