Way back when I was writing Delphi, there was a TStringList which was basically a map of strings to Delphi's generic TObject. Using this structure, I could easily make a recursive, hierarchical structure by placing another TStringList against one of the string keys:
ParentStringList["somekey"] = "just a string value";
ParentStringList["anotherkey"] = SomeChildStringList;
Question is, how do I achieve the same thing in C++?
What I have at the moment is:
typedef boost::variant< std::string, my_dictionary > my_variant;
typedef std::map < std::string, my_variant > my_dictionary;
... which is clearly circular.
Can I do this without wrapping things in structs (which I can forward declare), or without using pointers (which the compiler knows the size of)?
The Boost.Variant documentation covers this exact case. You can't do it without using pointers or some other similar wrapper.
This approach could work:
struct my_variant;
typedef map<string,my_variant> my_dict;
struct my_variant: variant<string, my_dict>
{};
There are a few issues with it though:
This requires containers (std::map specifically) that allow template arguments that are not fully defined. Using C++98, this is explicitly forbidden, I'm not sure if this was lifted in later C++ versions.
Publicly deriving from containers is not usually a good idea, please research the reasons for that yourself and how they apply to your program. Using containment instead of derivation would be a safer alternative, or the middle way of private derivation, but that breaks the useful IS-A relationship that this approach provides.
Try using vectors. I've used them before as internal representations of an external database within my program as a data structure.
Related
I've been wondering, is there any reason for the design decision in C++ to not have a pure abstract class for any of the std library containers?
I appreciate that hash_map came later from the stdext namespace but shares a very similar interface. In the event that I later decide I would like to implement my own map for a particular piece of software, I would have preferred to have some kind of interface to work with.
Example
std::base_map *foo = new std::map<std::string, std::string>;
delete foo;
foo = new stdext::hash_map<std::string, std::string>;
Obviously the above example is not possible, as far as I am aware, however this is similar for list and other std lib containers.
I appreciate that this is not C# or Java, but there is obviously no constraints in C++ to stop this design, so why was it designed like this so that there is no coupling between similar containers.
Because virtual functions add overhead.
Because the containers don't all have the same interface, there are common functions but also important differences regarding iterator invalidation and memory allocation (and so exception behaviour) which you need to understand, if you were using an abstract base you wouldn't know the specifics of how the concrete container would behave.
If you want to write code that is agnostic about the type of container it is passed then in C++ you write a template instead of relying on abstract interfaces, i.e. use static polymorphism not dynamic polymorphism. That avoids the overhead of dynamic dispatch and also allows specialization based on concrete type, because the concrete type is known at compile time.
Finally, it wouldn't have any advantage IMHO. It's better the way it is. As you say, this isn't C# or Java, thankfully.
(P.S. the stdext namespace is not part of C++, it appears to be Microsoft's namespace for non-standard types, a better example would use std::tr1::unordered_map or std::unordered_map instead of stdext::hash_map)
Is Typelist(in the sense of Alexandrescu define it) mainly/essentialy useful for generate hierarchy of class (and maybe for class like boost::tuple )
or is there plenty of other domains where typelist is very useful ?
Its also used in Mixin-Based Programming in C++ described by Ulrich W. Eisenecker, Frank Blinn, and Krzysztof Czarneck.
I believe you're referring to something like a linked list of templates.
This is a fundamental structure in template metaprogramming. Template metaprogramming has various applications, where the programmer encodes a problem in templates and the metaprogram implements an algorithm to solve it.
Boost Spirit is often cited as a prime example of template metaprogramming, although unfortunately I can't tell you much about it.
It seems to me that typelists are most useful as a building block for other generic libraries rather than being used directly in client code. Don't use a lower-level tool if Boost tuples or MPL are flexible enough to do what you need. But there's nothing to say you couldn't use typelists directly if you need that kind of flexibility.
We use a typelist as a sort of type-safe composition, but where each child is accessible through a single interface:
// Defining a typelist:
typedef TypeList<A,
TypeList<B,
TypeList<C, NullType> > > MyTypeList;
MyTypeList tl;
// Setting values in the typelist:
A a;
tl.set(a);
C c;
tl.set(c);
tl.tail().head() = newB;
// Retrieving values from the typelist:
C c = tl.get<C>();
B b = tl.tail().head();
// To reinitialize a value:
tl.reset<B>();
tl.set(B());
// To get total size:
int size = tl.count();
Beyond that, there's an interface for iterating and built-in support for functors.
The benefit is that you can either treat the children independently or homogeneously, depending on the need.
The downside is that you sacrifice a certain amount of abstractness. Things become much more concrete. It also introduces a new way of dealing with composition, which is something new to learn for others who need to work with the code.
For us, in the place we used it, it was a good fit.
1) What is the convention used in practice when typedef'ing
something like
typedef std::map<SomeClass*, SomeOtherClass> [SomeStandardName>]
typedef std::map<SomeClass*, std<SomeOtherClass> > <[SomeStandardName]
2) Where do you usually put typedef: header files globally, local to the class?
3) Do you typedef iterators or const map<> version?
4) Say you have map that used by two different concepts, do you create two separate typedefs them?
typedef map<string, SomeClass *> IDToSomeClassMap;
typedef map<string, SomeClass *> DescriptionToSomeClassMap;
Thanks
Edit #1
I am interested specifically in typedef STL maps, such as
typedef map<int, string> IdToDescriptionMap
or
typedef map<int, string> IdToDescription
What are common practices?
I prefer the following convention:
typedef std::map< Foo, Bar > FooToBarMap
I purposely avoid typedef'ing the iterators, I prefer explicitly referring to them as:
FooToBarMap::const_iterator
Since the iterators are already a de facto standard typename. And FooToBarMapConstIter is actually less clear to read when skimming code, I find.
There is no generally agreed rule on these names. What I usually do is to use the name of the "value" class suffixed with Map. In your example that would be SomeOtherClassMap. I use this convention because it is usually more interesting that your map contains "value" objects of type SomeOtherClass then that you look them up with "keys" of SomeClass.
The second part of the question is the most interesting one to me. I prefer to put typedefs within the classes that use them, when there's a logical place for them, even if they're used in other classes. But that causes some problems with forward declarations (which we use heavily for compile-speed).
For example, in one recent project we had a class called Io, with an embedded typedef called Point, which made for very readable code -- an Io::Point is very clear and readable. But whenever we wanted to use the type, we had to include the declaration of the Io class, even if all we needed was the declaration of Io::Point, since there's no way (that I know of) to forward-declare a type that's within a forward-declared class.
In that case, we ended up doing it both ways. We created a global IoPoint type, and then typedefd Io::Point to it (so that our already-written code didn't have to be modified). Not the prettiest answer, but it got the job done.
As for the other parts:
We don't use any special convention for the names. For maps, we often use *DescriptiveSomething***Map** (since it's unlikely that we'll ever change from a map to some other container type), but if DescriptiveSomething is descriptive enough and doesn't conflict with an existing name, we'll often use it instead.
We generally don't bother creating typedefs for the iterators, since it's easy (and very readable) to simply use Type::iterator or Type::const_iterator. That said, we do sometimes typedef them if the type name is so long that Type::const_iterator makes the code look too "chunky." (Don't know of any better way to say it, but you probably know what I mean.)
We create different typedefs for each concept, even if two of them define exactly the same type. They can change independent of one another, so having different type names for them simplifies any later refactoring. It also makes for more readable code, in many cases.
I don't know if there are any formal rules on the subject but I usually add type defs at the location most befitting the use within the project.
If the typedef is only used within one class then add the typedef inside the class definition
If the typedef is used by several unrelated classes add it in a header file at a namespace scope level
As for the actual name of the typedef'd type. I name it whatever makes sense for the typedef. I don't give typedef names any special convention such as prefixing with _t or anything along those lines. For example
typedef stl::map<stl::string,Student> NameToStudentMap;
None, just keep in mind the general rules for naming identifiers (no _ to begin with etc). Also, if your organization has a coding guideline, it is best to stick to it.
Often, when defining your own template class, it becomes messy without typedefs -- so I'd create them there as handy shortcuts. However, if it's really a bunch of classes, I'd rather have it at namespace level.
We use the following at my workplace:
typedef std::map WhateverMap;
typedef WhateverMap::iterator WhateverIter;
typedef WhateverMap::const_iterator WhateverCIter;
As far as location goes, that varies. If it's class-specific, it may be in an Impl structure, or may be in the protected or private areas of the class declaration. If it's more general (used across files, used in an API), we put it in a separate "FooTypes.h" style header.
Note that since it's common for us to sometimes change the underlying type, we may use "WhateverCollection" instead of "WhateverVec" or "WhateverList". It's not uncommon to have a "WhateverList" actually be typedefed to a vector or an slist, depending on desired footprint and performance characteristics.
Interest question:
I looked in boost, and I see they haven't any global rule, but most used convention
typedef std::map< key, value > some_domain_specific_name_map;
or
typedef std::map< key, value > some_domain_specific_name_map_type;
also good practice to make typedef for value_type or iterators, usually they have same name as map but with ending _value_type, _iterator.
Normally I define related name to the typedef indicating the type of the object .
Ex:
typedef std::vector<ClassCompStudent*> StudentCollection;
typedef std::map<std::string /*id*/, ClassCompStudent* /*pStudent*/> IDToStudentMap;
Also, I define them as public in class header in which the object has been created. That gives me the benefit of changing the container type without breaking client code.
class Test
{
public:
typedef std::vector<ClassCompStudent*> StudentCollection;
/* Users of Test need not know whether I use vector or list for
storing students. They get student collection and use it*/
bool getStudents(StudentCollection& studentList) const;
void print()
{
//do printing
}
private:
StudentCollection m_StudentList;
};
bool function(const Test& testObj)
{
//If StudentCollection gets changed to list, this code need not be changed.
StudentCollection aCollection;
testObj.getStudents(aCollection);
std::for_each(aCollection.begin(), aCollection.end(), std::mem_fun(&Test::print));
}
Using word "Map" or "Vector" in kind of useless notation. These are words connected to realization and not to the business model.
You don't have to show that this type is vector or map. You can use List. Like
typedef std::vector<std::string> List;
typedef std::set<std::string> List;
These both are lists of string. And this is true.
typedef std::map<std::string, Object> List;
or
typedef std::map<std::string, Object> NamedList;
My point is don't use kind of hungarian notation.
This question already has answers here:
Closed 14 years ago.
When should someone use structs instead of classes or vice versa in C++? I find myself using structs when a full-blown class managing some information seems like overkill but want to indicate the information being contained are all related. I was wondering what are some good guidelines to be able to tell when one is more appropriate than the other?
Edit:
Found these links while reading the material Stack Overflow indicated was related after the question was submitted:
When should you use a class vs a struct in C++?
What are the differences between struct and class in C++?
Technically, the only difference between the two is that structs are public: by default and classes are private:
Other than that, there is no technical difference.
struct vs class then becomes a purely expressive nuance of the language.
Usually, you avoid putting complicated methods in a struct, and most of the time structs data members will stay public. In a class you want to enforce strong encapsulation.
struct = data is public, with very simple helper methods
class = strongly encapsulated, data is modified / accessed only through methods
I use structs for simple containers of types that provide no constructors or operators.
Classes for everything else.
Use a struct when you simply need a "bucket of stuff" that doesn't have logical invariants that you need to keep. Use a class for anything else.
See also what the C++ FAQ says on the subject.
Use a class if you have methods, a struct if not.
A class should hide all its internals only exposing methods or properties. A struct tends to expose all its internals and has no accessor methods.
Where only one bit of code is accessing some (related) data, a struct may be perfectly reasonable. Where multiple bits of code need to modify the data or if it's anything slightly complicated, a class would be a better bet.
The difference between Classes and Structs are that structs are groups of variables and classes represent objects. Objects have attributes AND methods and be part of a hierarchy.
If you're using C++ to take advantage of the OO capabilities it's best to use classes / objects which are more natural.
I always use class, even for just containers, for consistency. Its purely a choice of style since the difference between the two is negligible.
If you need to control access to the data, you should use classes. If you don't care who is accessing what, and what they're storing in there, then a struct is probably more appropriate.
Also, a class is more appropriate if you need to do any checks on the integrity of the data itself.
See existing questions:
What are the differences between struct and class in C++
When should you use a class vs a struct in C++?
Personally, I use structs when all I need is a container for data (no member functions).
Otherwise, I use classes.
The only time I make an exception to that rule is if I need a simple functor: e.g.
struct compare { bool operator() { ... } };
sort(v.begin(), v.end(), compare());
The need for a public: label would just clutter up the code unnecessarity.
structs in C++ are classes with a default access method of public, so technically other than that default there is no difference and you can use both equivalently.
Yet there are some expectations and natural tendencies, in part because structs in C++ come from C.
My approach: If it has any private data, a constructor/destructor, or any complex member functions (which do more than just conversion upon set/get, etc.), use class.
What are the advantages of using boost.any library ? Could you please give me some real life examples ? Why the same functionality couldn't be achieved by having some generic type in the root of object's hierarchy and creating containers with that base type ?
boost::any will happily store ints and floats, types that clearly have no base classes. A real-life example where you can use it is a virtual machine for a high-level interpreted language. Your "function" objects will need an array of arguments. This can easily be implemented with a std::list<boost::any> behind the scenes.
I consider that Boost.Variant should always be preferred as it's non-intrusive and still calls for very structured programming.
But i guess the main idea behind boost.any is to provide the equivalent of java and c# object types. It's a way of saying "yes we can" ! :-)
We've used it in a property map, (std::map<std::string, boost::any>), to store a lot of things dynamically in a simple, flat dataspace.
Mostly we either stored smart-ptr-to-scriptable-objects or strings, but some entries where other types (floats, vec3f, matrices, and other non-standard objects).
It works pretty well for adding more dynamic capabilities to c++, or wherever you want some type-erasure to just add any type of data to an object.
Why the same functionality couldn't be achieved by having some generic type in the root of object's hierarchy and creating containers with that base type ?
That calls an object hierarchy -- a construct you are injecting in artificially in to the design for solving a peripheral problem. Further, such a construct is easy to get wrong and a wrong implementation can wreak havoc. Boost.Any is a community reviewed safe, well-tested alternative.
Could you please give me some real life examples ?
TinyJSON uses boost.Any.
What are the advantages of using boost.any library ?
I refer the introductory documentation.
We use boost.any as the carrier type for a type-safe tagged variadic container. Here's what that means:
We have a "raft" object, which travels through a set of filters. When a filter wants to add data to the raft, it can do something like this:
raft.addTaggedData<ETag1>(3.0);
raft.addTaggedData<ETag2>("a string")`;
std::string str = raft.getTaggedData<ETag2>();
int a = raft.getTaggedData<ETag1>(); // <-- Compile error
Where ETag1 and ETag2 are members of an enum, and we use a traits template to map tags to types.
The raft class is using a list of pair<ETagType, boost::any> as a backing store. Boost.any saved us the pain of managing raw buffers for various types.