To begin with, I'm new to C++/OOP.
I want to include a std::map in my class and am wondering about how to provide users of my class the map typedefs and capabilities. Do I need to do as in the simple example below? (I've only shown a subset to indicate what I'm trying to do)
It doesn't feel right that I have to do this for any class where I've included a container (even for a subset of map methods).
It also seems like a class maintenance issue (e.g. might not need some map method today, but it becomes needed in the future)
p.s. aside from replying to this question, any other corrections/feedback to the example below are appreciated.
#include <map>
#include <string>
class Inventory {
public:
typedef std::string key_type;
typedef std::string mapped_type;
typedef std::map<key_type, mapped_type>::value_type value_type;
Inventory() { }
Inventory(int lotNum) : lotNum_(lotNum) { }
void insert(const value_type& el) { cars_.insert(el); }
//
// TODO: iterators, erase, etc
//
private:
int lotNum_;
std::map<key_type, mapped_type> cars_;
};
int main() {
Inventory ourCars(1);
ourCars.insert( Inventory::value_type( "BMW","ABC123" ) );
return 0;
}
Here is how I would think about this problem. Think of your class interface and implementation separately. The user shouldn't need to know what you're doing behind the scenes - what containers you're using etc. Your class itself should have some functionality that you provide through its interface. I'm not sure what your class is supposed to do, but if you want a function to insert two strings you should just provide that function. That's your starting point. Then you decide that you're going to store your strings in a map or whatever. In summary, the types that go into the map will be decided by your class interface. What you're doing is the opposite - deciding how you're implementing it and then exposing the types of your map in the interface.
Related
For a program which is a simple rogue-like game, I need a container for storing contents of each room be it enemies, loot, traps, lore-entries etc. Since set of types being held in each room is finite and predetermined I've settled for std::variant for data storage. I also will need methods to process the data and here comes the problem. Now due to lack of experience I struggle to choose realization that won't become a burden in long term.
Objective style approach:
using myVariant = std::variant<TYpe1, Type2 ... TypeN>;
template <typename V>
class HVector
{
private:
class HVElem
{
private:
V data;
public:
V getData();
};
std::vector<HVElem> content;
public:
void push(V newData);
};
int main()
{
HVector<myVariant> hVector;
}
Functional approach:
using myVariant = std::variant<TYpe1, Type2 ... TypeN>;
template <typename V> void push(std::vector<V> hVector, V newData)
{
// something
}
int main()
{
std::vector hVector<myVariant>;
}
Questions:
Which of the two approaches is better? I have a strong feeling that simply using std::vector<std::variant<>> with some template functions is enough in this case. Is using objective style even requiered here?
How can I prevent the program from creating a container that holds anything other than std::variant<>? Is there a way to simply list types in type aliases so that I could simply write std::vector<std::variant<myTypes>>?
Which of the two approaches is better?
Neither, see option 3 below.
How can I prevent the program from creating a container that holds anything other than std::variant<>?
using myVariant = std::variant<TYpe1, Type2 ... TypeN>;
using myVector = std::vector<myVariant>;
I am trying to design a data stuctures, which would enhance/supplement an existing one by storing some additional data about it's members.
Let's say we have:
class A {
int x;
string y;
};
And we want to have a GUI component associated with it, so the data members have corresponding GUI elements. I'd like to map the members to their respective components. Something like
class GuiA {
int x;
string y;
map<MemberHandle, GuiElement*> guiHandles;
}
I don't have any restrictions, but I'd like the result to be easily convertible to the original type.
I am aware, that I could introduce a template e.g. GuiElementMember holding original data plus the GuiElement pointer, and swap class member for their decorated counterparts, so it would look like:
class GuiA {
GuiElementMember<int> x;
GuiElementMember<string> y;
}
but I'd like to avoid it, as it completely changes access patterns to data members and bloats it. I.e. it results with data members interleaved with pointers, that are not easy to strip out.
Ideally it would be possible to write GuiA as a derived class of A, or as a composition of A and something additional.
I was thinking about something like a template that class could produce the map. I could yield to write a custom class per component, but I don't think there is an easy way to map data members, so on the clients side it would look like getGuiMember(GuiA::x). The pointer to data member contains the member original type. I don't think it is possible to have something like "type-erased pointer to member" that could serve as a MemberHandle type.
The only thing that comes to my mind is a custom enum per component which would enumerate data members and serve as key type for a map (or a vector in this case), but it seems as an awful lot of information duplication and maintenance.
Is there some technique that allows mapping data members?
I don't really care about the implementational complexity as long as the interface is easy. I welcome boost or template magic. I also don't care about the performance of additional data access, it's extra stuff, but the plain class usage should not be impacted, so introduction of indirection that cannot be optimized is less welcomed.
EDIT: Please don't hinge on GUI thing it's an example. I am only concerned about storing some additional data per member without composing it with the member.
You can use BOOST_FUSION_DEFINE_STRUCT to define your structures that can be iterated over with a for_each loop:
#include <boost/fusion/include/define_struct.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <unordered_map>
#include <string>
#include <cstdint>
BOOST_FUSION_DEFINE_STRUCT(
(demo), employee,
(std::string, name)
(int, age)
)
struct GuiElement;
GuiElement* createGuiElement(char const* name);
using Mapping = std::unordered_map<size_t, GuiElement*>;
template<class T>
Mapping create_mapping(T&& t) {
Mapping mapping;
boost::fusion::for_each(t, [&](auto& member) {
auto offset = reinterpret_cast<uintptr_t>(&member) - reinterpret_cast<uintptr_t>(&t);
mapping[offset];
});
return mapping;
}
template<class T, class M>
GuiElement*& get_mapping_element(Mapping& mapping, T const& t, M const& member) {
auto offset = reinterpret_cast<uintptr_t>(&member) - reinterpret_cast<uintptr_t>(&t);
auto found = mapping.find(offset);
if(found == mapping.end())
std::abort();
return found->second;
}
int main() {
auto employee_mapping = create_mapping(demo::employee{});
demo::employee e1;
get_mapping_element(employee_mapping, e1, e1.name) = createGuiElement("name");
get_mapping_element(employee_mapping, e1, e1.age) = createGuiElement("age");
}
In the code there is a Mapping, one per class. Each member is identified by its offset from the beginning of its enclosing class.
In general, you use macros for such purposes. They can generate any kind of code/wrappers that you'd like, letting you have the usual access to your data, but also adding stuff you want/need. It ain't pretty, but it works.
There are some template libraries that can help here, like Boost.Fusion or Boost.Hana, but, you can also roll your own here if you don't have a use for their advanced features (which come with the long compilation price tag).
Also, if you can focus on a particular GUI framework, they have some support for such things. For example, Qt has its own "meta object" compiler.
You could try a template for this?
e.g.
template <typename T>
class GuiItem : public T {
map<MemberHandle, GuiElement*> guiHandles;
}
GuiItem<A> guiA;
guiA.x = 123;
guiA.y = "y";
guiA.guiHandles[handle] = element;
I'm not sure I understand the other requirements so this way may not work for you.
I have stumbled upon some weird use of priority_queue, I would love to obtain some proper explanation of why on earth it's plausibile/valid to use something like this in priority_queue declaration:
typedef priority_queue<RandomContainer, **vector<RandomContainer>**, FunctorName> NewQueueName;
Let's say we've got some struct called SPerson:
struct SPerson
{
int age;
string name;
string surname;
};
and some functor which will be helpful to sort all elements of queue accordingly to our likeing:
struct TheWayILike
{
bool operator()(const SPerson &name1, const SPerson &name2)
{
if(name1.name > name2.name) return true;
if(name1.name < name2.name) return false;
return false;
}
};
Now we can declare our priority_queue which will be based upon elements from the struct and which will be ordered by functor called TheWayILike.
priority_queue<SPerson, TheWayILike>
or shorter way by using typedef and single name like so:
typedef priority_queue<SPerson, TheyWayILike> newNameForPQ;
but somehow it's wrong and I have to add following line: vector
Question:
Why on earth do I have to squize my personally customized data types into vector ?
Why it must be a vector and why should I use it anyway ?
Why do I need to fill my data into vector ? I haven't read about it in official priority_queue documentation, so I would love to obtain some easy to understand explanation for rookie programmer.
Cheers!
You dont' have to. But look at the declaration of the priority_queue class template:
template<
class T,
class Container = std::vector<T>,
class Compare = std::less<typename Container::value_type>
> class priority_queue;
You can't provide a custom comparator type argument unless you also provide the underlying container to hold the data in. The author of the line above decided vector was the best choice. Any other container that fits the requirements can also be used, e.g. deque, but vector proves to be best for most applications so it is the default.
I very often run into the problem that I want to implement a data structure, and would like to allow users to extend it with functional functionality; that is add functionality but not bytes to the data structure. An example could be extending std::vector with a sum method:
#include <iostream>
#include <vector>
// for the header file
template<>
int std::vector<int>::sum();
//for the object file
template<>
int std::vector<int>::sum() {
int s=0;
for(auto v = this->begin(); v!=this->end(); ++v) s+=*v;
return s;
}
int main() {
std::vector<int> numbers;
numbers.push_back(5);
numbers.push_back(2);
numbers.push_back(6);
numbers.push_back(9);
std::cout << numbers.sum() << std::endl;
return 0;
}
See: http://ideone.com/YyWs5r
So this is illegal, since one may not add functions to a class like this. Obviously this is some design decision of c++(11). It can be circumvented in two ways, that is defining a
int sum(std::vector<int> &v) { ... }
This is how std::sort works, so I guess it is the way c++(11) is intended. I think this is to the best of my knowledge the best way to do it in c++. However, it does not allow me to access private properties of std::vector. Maybe I am evil by assuming access to private properties in a (sort-of) method is fair. However, often I want users of my classes to not access certain stuff, however would like to allow extenders of my to access them. For example I can imagine that std::sort can be optimized w.r.t. specific container implementation knowledge and access.
Another way is inheriting std::vector, but I find that plain unacceptable for these reasons:
if two parties have extended the class with methods, which one would like to use, then one would need to convert from one child class to another. This is ludicrous, as one converts data to data without actually changing bytes, as both child classes (can) have exactly the same memory implementation and segmentation. Please also note that data conversion in general is boilerplate code, and boilerplate code should imho be considered evil.
one is unnecessarily mixing functionality with data structures, for example, a class name sum_vector or mean_vector is completely.
As a short reminder, I am not looking for answers like "You cannot do that in c++", I already know that (Add a method to existing C++ class in other file). However, I would like to know if there is a good way to do functional class extensions. How should I manage accessing private fields? What would be reasons why it is unreasonable for me to want private field access; why can't I discriminate between extender and user access?
Note: one could say that an extender needs protected access and a user needs public access, however, like I said, that would be for the inheritance way of extending, and I dislike it strongly for the aforementioned reasons.
You never should want to access private members of Standard Containers because they are not part of their interfaces.
However, you already can extend the functionality of the Standard Containers like std::vector: namely through the judicious use of iterators and Standard Algorithms.
E.g. the sum functionality is given by a non-member function that uses the begin() and end() functionality of std::vector
#include <algorithm>
#include <iterator>
#include <vector>
template<class Container, class Ret = decltype(*begin(c))>
Ret sum(Container const& c)
{
return std::accumulate(begin(c), end(c), Ret{});
}
Consider something like this:
#include <iostream>
class Foo{
int a;
public:
Foo(int a){this->a = a;}
int getA(){return this->a;}
void * extendedMethod(void *(*func)(int, char **, Foo*), int argc, char **argv){
return func(argc, argv, this);
}
};
void * extendFooWith(int argc, char **argv, Foo* self){
/* You can call methods on self... but still no access to private fields */
std::cout << self->getA();
return self;
}
int main(int argc, char const *argv[])
{
Foo foo(5);
foo.extendedMethod(extendFooWith, 0 /*argc*/, NULL /*argv*/);
return 0;
}
That's the best way I thought of extending a class with a method. The only way to access private fields would be from inside extendedMethod() i.e. something like this is possible: return func(this->a, argv, this); but then it is not that generic any more. One way to improve it could be checking inside extendedMethod() what kind of pointer was passed and according to it access the private fields you are interested in and pass those to func(), but this will require adding code to extendedMethod() for every other method you will extend your class with.
I'm very new to using maps in C++, so I am having some difficulties using it for my SDL surfaces. This is what I've tried (not working):
map <SDL_Surface*, char*> mSurfaceMap;
mSurfaceMap.insert(pair<SDL_Surface*, char*>(m_poSurfaceTest, "..//..//gfx//testImage.png"));
The idea is to put all surfaces and their corresponding image files in a map to easily initialize them and do IMG_Load() on them, as well as free them when closing the program.
If this is a bad solution for it, please point me in the right direction. I first thought of making two arrays, but I wanted to try this instead, as I felt it was a more elegant solution. If the solution is ok, I'd love to hear what I am doing wrong in the code.
This code works for me. Output is as expected:
#include <map>
#include <stdio.h>
using std::map;
using std::pair;
struct Custom
{
int val;
Custom() {val=0;}
};
int main(int argC,char* argV[])
{
map<Custom*,char*> mMap;
Custom* test = new Custom;
mMap.insert(pair<Custom*,char*>(test,"Test"));
printf("%s\n",mMap[test]);
return 0;
}
std::map is great for looking up data by an ordered key, it is usually implemented as a balanced binary tree that gives O(log n) look-up time. If the look-up order doesn't matter then a std::hash_map will be a better choice with an O(1) look-up time.
The problem with using a pointer as your key in either container is that the they will index by the integer address of the pointer, not the value of what is pointed to.
std::string, however, has value semantics and implements the less-than operator which will let the container index by the value of the string.
You may also want to put your surface in a smart pointer for memory management purposes.
typedef std::tr1::shared_ptr<SDL_Surface> surface_pointer;
typedef pair<std::string, surface_pointer > surface_pair;
std::map<std::string, surface_pointer > mSurfaceMap;
mSurfaceMap.insert(surface_pair("..//..//gfx//testImage.png", surface_pointer(m_poSurfaceTest)));
A couple of other thoughts...
If you don't need the look-up functionality, and are just using a container for housekeeping, then a simple std::vector<std::pair<std::string, SDL_Surface*> > would probably suffice for what you need.
Or, if you're storing the surfaces as members already (assuming from the variable name) then you could store the member variables as a tr1::unique_ptr<SDL_Surface> and when the containing class is deleted so will the SDL_Surface be deleted. For this to work however you need to provide a custom deallocator for the tr1::unique_ptr, that will teach it how to free an SDL_Surface*.
struct SdlSurfaceDeleter {
void operator() (SDL_Surface*& surface) {
if (surface) {
SDL_FreeSurface(surface);
surface = NULL;
}
}
};
Then you would specify your members like this (a typedef makes it less verbose):
typedef std::tr1::unique_ptr<SDL_Surface, SdlSurfaceDeleter> surface_ptr;
class MyClass {
public:
MyClass(const std::string& path)
: m_poSurfaceTest(IMG_Load(path.c_str()) { }
surface_ptr m_poSurfaceTest;
};