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.
Related
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.
I have an application that I'm porting from C++ to Java. There is a section C++ code that I find really strange.
typedef std::string ArgName;
typedef std::map< ArgName, AnyData > ArgumentMap;
class Arguments : public ArgumentMap
{
public:
// Very important note: When read finds a numeric/set argument,
// it sets anyData.kind to Int. But STILL, it fills anyData.dString,
// just in case. So if the ArgumentMap was built by Arguments::read,
// the dString fields are all filled.
bool read( int argc, char **argv );
// remains is filled with the arguments not starting with '-'.
bool read( int argc, char **argv, std::vector<const char*>& remains );
// const if fails, erases arg if succeeds.
bool getNumericParam( const ArgName& name, int& num );
// sw is true if the switch is present. The function
// returns false if the argument value is not empty.
bool getSwitch( const ArgName& name, bool& sw );
bool getSwitchConst( const ArgName& name, bool& sw ) const;
// Returns true if the switch is present. Throws an error message if
// if the argument value is not empty.
bool getSwitchCompact( const ArgName& name );
void checkEmptyArgs() const;
};
It looks like in there original C++ the author is making their Arguments class inherit from a Map. This makes no sense to me. Map is an interface which means you can't inherit from it, you can only implement it. Is this something that can be done in C++ that you can't do in Java?
Also, I don't understand why you would use a typedef. I read the definition from Wikipedia
typedef is a keyword in the C and C++ programming languages. The purpose of typedef is to
form complex types from more-basic machine types[1] and assign simpler names to such
combinations. They are most often used when a standard declaration is cumbersome,
potentially confusing, or likely to vary from one implementation to another
But I don't understand why the author would do that here. Are they trying to say that they want to inherit from the class AnyData and that ArgumentMap should have a Map as one of its fields?
This makes no sense to me. Map is an interface
In Java, it is. In C++, it's not even a class, it is a class template. C++ does not have a concept similar to Java's interfaces, although you can implement something similar with virtual inheritance.
As far as the collection classes are concerned, C++ solved with templates and generic programming what Java solved with interfaces and inheritance.
Instances of C++ map template are fully functioning classes that work similarly to Java's TreeMap. You can inherit them in the same way that you inherit from classes in Java, and because of multiple inheritance, you are not limited to a single class.
Also, I don't understand why you would use a typedef.
You use typedef to give classes meaningful names. In addition to shortening your typing, it makes your program more readable, and gives you additional flexibility at redefining the class behind the typedef later on.
Note: the fact that you can inherit from standard containers does not mean that you should do it. Read answers to this question for more information.
Interfaces are a language construct specific to Java. They do not exist in C++. In C++ you only have classes. You can have abstract classes (classes with unimplemented methods), and eventually you can use them to enunciate interfaces.
C++ has multiple inheritance, there are no "interfaces". You can certainly inherit from any class. And C++ has templates, something completely absent in Java. Templates allow you to make the compiler write specially tailored functions or classes.
Map isn't an interface, it's a template. Moreover - the author doesn't derive his class from the map template as a whole, but he derives from a parametrized template. Without the code of the class, one can only guess why he's doing it, and what he wants to achieve.
Note that deriving from STL templates is a bad idea in general (with few exceptional cases) and usually it's much better to make the template a member of your class. Templates don't have virtual members and thus - there's no real way to change their behaviour when deriving (and that's the real point of inheritance in many cases).
And a bit about the typedefs: when you use a typedef like that, you make your code a bit easier to change in the future. When you (For any reason) decide that you want to implement your own string class, you only need to change the first line in this file (from typedef std::string ArgName; to typedef myNewStringClass ArgName;), instead of changing the code in all the places where ArgName occurs.
Coming from the Java world, in which there are no typedefs, I have a question for C++ developers:
My task is to rewrite a large MATLAB project in C++. In order to get to know the structure of the code, I have started rebuilding the module and class structure without actually implementing the functionality.
I know that I frequently need classes/types like Vector and ParameterList, which will be provided by some framework I have not decided on yet.
So I created a central header file Typedefs.h in which I have type definitions like
typedef void Vector; // TODO: set vector class
typedef void ParameterList; // TODO: set parameter list class
For now, these are set to void, but I can use these types to write class skeletons and method signatures. Later I can replace them with the actual types.
Is this something that makes sense? If yes, is there a way to avoid manually including the Typedefs.h in every file?
I doubt this would work, unless you use, for example Vector*. You wouldn't be able to have Vector objects or parameters, so it's pretty much pointless.
And for use as a pointer, you can very well do a forward declaration.
Anyway, I don't really see the need for any of this. You can declare an empty class without having to implement it, and it's even easier to write than a typedef:
typedef void Vector;
vs
struct Vector{};
Note that you will not be able to overload functions with typedefs that map to the same type:
void foo(Vector);
void foo(ParameterList); // error: foo(void) already declared
I couldn't find anything relevant, but sorry if this has been asked already. I sometimes find myself in a sitution in which I have a class, that contains internally say two different containers. Something like the following:
class Foo
{
public:
typedef std::vector<int> int_list;
typedef std::vector<X> x_list;
// It would be nice if the user could iterate through these etc. so that I
// could define functions that operate on them as non-member non-friends.
typedef int_list::size_type int_list_size_type;
typedef int_list::const_iterator int_list_const_iter;
typedef x_list::size_type x_list_size_type;
typedef x_list::const_iterator x_list_const_iter;
int_list_const_iter int_list begin() const { return ints_.begin(); }
x_list_const_iter begin() const { return xs_.begin(); }
int_list::size_type size_of_ints() const { return ints_.size(); }
x_list::size_type size_of_xs() const { return xs_.size(); }
// And so forth ... !
private:
int_list ints_;
x_list xs_;
};
Somehow I feel uneasy. Is this is a smart way of doing what I'm doing? Basically, for every container I would need typedefs and (const overloaded) begin and end methods etc. I'm curious: what would be your way of designing the interface, naming the typedefs etc? I guess I'm basically worried about the interface and the explosion of methods, and it looks kinda ugly too.
Maybe one way of limiting the number of begin/end methods would be a template-based approach using somekind of tags, but I'm not sure if that's sensible.
Thanks!
It sounds like your class is doing too much. If your clients need to do all those kinds of operations on those containers, it's probably best if you just expose a constant reference to the container itself instead of trying to wrap every STL interface yourself.
On the other hand, if your clients need to do all those things it's probably a sign that the class needs to be broken apart into smaller classes.
Have you actually tried this? You code won't compile. You can't have two functions with the same name/param list that return different things.
As to the intent...your misgivings are appropriate and your class is probably not doing enough of its own work to warrant its existence. The very fact that you want to expose the complete internals of the object so clients can work on them make me conclude that your class is almost certainly 100% useless. It's a design issue and your misgivings are simply your nose telling you something stinks.
You should not allow access to the containers. You should export the functionality of the class, and the class should have a central point. Assuming the class is using the containers, e.g. int is a key that references X, you will probably need an interface that coordinates access. In this case you should not provide access to the underlying containers.
Consider one has some user defined types, and containers of those types that are often manipulated because there are often multiple instances of those types on screen at a time.
Currently I have a header with an associated source file and a namespace to hold these containers, but should I create a separate class to hold them? Should I put the containers in the same header file as the class that they contain (but obviously outside the class)? What is the standard practice for situations like this?
I once typedef'd them whenever a specific class has the container as part of that class's interface. Then anyone who needed to use that class easily figured out that a "FooVec" is a std::vector of Foo without a lot of fus.
However, this is an imperfect solution, consider the following code:
namespace bar
{
typedef std::vector<Foo> FooVec;
class CClass
{
CClass(FooVec&)
{
...
}
};
}
Naturally the problem comes in when your colleague redefines FooVec for their class:
namespace bar
{
typedef std::vector<const Foo> FooVec;
class CAnotherClass
{
CAnotherClass(FooVec&)
{
...
}
}
};
The simplest thing I've found to solve this is to have them in roughly one common include per namespace/library/group of associated classes. So when someone else adds a typedef to something in the bar namespace, you can have them all in one place. IE:
barTypes.h
namespace bar
{
typedef std::vector<Foo> FooVec;
typedef std::vector<const Foo> FooConstVec;
}
By keeping it to one header per small set of classes (ie per namespace) you don't get a gigantic file full of typedefs. It still gives your users good visibility into the types that are a part of your class's interface. Once this header is established, its just a matter of maintaining discipline on your team to use it instead of establishing additional typedefs.
May also wish to have this header as part of a precompiled header if you're anal about build performance.