I hope to use std::map to store information for different datatype by type_index, learned from cppreference.com.
For example:
#include <typeindex>
class A{};
class B{};
int main()
{
map<type_index, string> info{
{type_index[typeid(A)], "Information for class A."},
{type_index[typeid(B)], "Information for class B."}
};
}
typeid() will return a struct type_info.
But I learnt that type_info.hash_code() may be not unique.Different type may have same hash_code.
I wonder if type_index is unique ?
Yes, std::type_index is unique. It's said to work as if it held a pointer to std::type_info.
Even though you can get different pointers for the same type, they're not compared directly. Rather, std::type_info::before() is used.
Related
See this link: https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(C4503)&rd=true It suggests to write:
// C4503b.cpp
// compile with: /W1 /EHsc /c
#include <string>
#include <map>
class Field{};
struct Screen2 {
std::map<std::string, Field> Element;
};
struct WebApp2 {
std::map<std::string, Screen2> Element;
};
struct WebAppTest2 {
std::map<std::string, WebApp2> Element;
};
struct Hello2 {
std::map<std::string, WebAppTest2> Element;
};
Hello2 MyWAT2;
instead of
// C4503.cpp
// compile with: /W1 /EHsc /c
// C4503 expected
#include <string>
#include <map>
class Field{};
typedef std::map<std::string, Field> Screen;
typedef std::map<std::string, Screen> WebApp;
typedef std::map<std::string, WebApp> WebAppTest;
typedef std::map<std::string, WebAppTest> Hello;
Hello MyWAT;
But those codes are not equivalent as with the typedefs Hello is an std::map while with structs it is just a struct that has a field which is a map which means I cannot use them interchangeably. Could someone explain the trick?
You're right, you can't use them interchangeably. In fact, Microsoft advise you to do so in order to overcome a technical difficulty from their end: they can't (or have difficulty to) handle mangled names longer than 4096 bytes.
In most case, a typedef would be a better solution over aggregation, I believe.
But since your compiler is somewhat limited, you may be stuck with their hack.
If you want a solution which fulfills the goal of differentiating the (mangled, possibly truncated) names, but without the downside of an extra layer of naming, you can use inheritance:
class Screen : public std::map<std::string, Field>
{
// forward constructors here
};
The workaround provided isn't to be meant as an equivalent replacement of the reproducer but rather as a possible way to reduce the decorated length of exported symbols.
You can verify with a simple objdump /symbols objfile.obj that the length of decorated symbols by using typedefs is incredibly longer than their similar counterparts split into structs (Microsoft compilers have historically used a proprietary name mangling scheme).
A typedef doesn't declare a new type, it just an alias. And if you forward-declare a typedef, when the compiler sees the typedef definition, it throws you an error:
// a.hpp
class Screen;
class any_class_using_screen {};
// a.cpp
#include "a.hpp"
typedef std::map<std::string, Field> Screen; // Error.
Using even simple inheritance allows you to use your custom names for other types:
class Screen : public std::map<std::string, Field>
{};
Remeber that simple inheritance without additional members doesn't cause any memory or time overhead. That is as efficient as a typedef, with the adventage that it is a new type.
Since std::map<...> hasn't virtual destructors, you cannot use the "pointer to base class" pattern as usual, of course. The owner of the Screen instance (the one who created a screen instance), if it lives in the heap and must be destructed, must be destructed from a pointer to the derived class:
template<class K, class V>
void f(std::map<K, V> const* map); // Do something
int main()
{
Screen* s = new Screen;
f(s); // Ok
delete s; // OK, deleting from derivate class
}
#PeterA.Scheneider suggest that, as far as the derivate class hasn't additional members, nothing happens, and you can call the destructor from a pointer to the derived class. But, theoretically, without a virtual destructor, you are destructing the base class instance (only the base class life reachs to its end), and the derivate class instance is still alive with a dead base, having a corrupted object. From a practical point of view, I think the object is correctly destructed, but anyway I don't know if that can cause undefined behaviour.
The standard should be check to be sure.
Additionally, there could be alignment issues with that approach of destructing, from a base class pointer, a derivated object without extra members.
If a base class has no virtual destructor, do inheritance without "polymorphic intentions", and destruct always from the most derived class.
I would like to have a std::hash_map that maps (for instance) regular std:strings to multiple different specializations of another template class.
This example is what I'm trying to achieve (it's wrong and doesn't compile, though):
template<typename T>
class Foo {
public:
Foo(T _value)
{
this-> value = _value;
}
private:
T value;
};
int main()
{
hash_map<string, Foo> various_foos;
various_foos["foo"] = Foo<int>(17);
various_foos["bar"] = Foo<double>(17.4);
}
The map can only store a single value type, so it can't directly store objects of different types; and different specialisations of a class template are different types.
Common solutions are:
Store pointers to a polymorphic base type, and access the real type via virtual functions or RTTI. You will need to be a bit careful about managing the objects themselves - either store smart pointers, or keep them in some other data structure(s).
Store a discriminated union type such as boost::variant or boost::any
You generally can't have an element in your hash that's of an incomplete type. Can you make a non-template base class that the others can inherit from?
The reason for this largely boils down to how the compiler will interpret your request. If it can't compute the size of your Foo structure, it can't create the internals for the hash_map.
Simple question: How do I get this to work?
struct A {
double whatever;
std::unordered_map<std::string, A> mapToMoreA;
}
g++ error: std::pair<_T1, _T2>::second has incomplete type
As far as I understand, when instantiating the map, the compiler needs to know the size of A, but it doesn't know this because the map is declared in A's declaration, so is the only way to get around this to use pointers to A (don't feel like doing that)?
Most of the time it will depend on the container implementation details (more precisely, on what gets instantiated at the point of container declaration and what doesn't). Apparently, std::unordered_map implementation requires the types to be complete. At the same time GCC's implementation of std::map compiles perfectly fine with incomplete type.
To illustrate the source of such difference, consider the following example. Let's say we decided to make our own naive implementation of std::vector-like functionality and declared our vector class as follows
template <typename T> class my_vector {
T *begin;
T *end;
...
};
As long as our class definition contains only pointers to T, the type T is not required to be complete for the class definition itself. We can instantiate my_vector itself for an incomplete T without any problems
class X;
my_vector<X> v; // OK
The "completeness" of the type would be required later, when we begin to use (and therefore instantiate) the individual methods of my_vector.
However, if for some reason we decide to include a direct instance of T into our vector class, things will chahge
template <typename T>
class my_vector {
T *begin;
T *end;
T dummy_element;
...
};
Now the completeness of T will be required very early, at the point of instantiation of my_vector itself
class X;
my_vector<X> v; // ERROR, incomplete type
Something like that must be happening in your case. The definition of unordered_map you are dealing with somehow contains a direct instance of A. Which is the reason why it is impossible to instantiate (obviously, you would end up with infinitely recursive type in that case).
A better thought through implementation of unordered_map would make sure not to include A into itself as a direct member. Such implementation would not require A to be complete. As you noted yourself, Boost's implementation of unordered_map is designed better in this regard.
I don't know of any STL containers other than smart pointers that work with incomplete types. You can use a wrapper struct however if you don't want to use pointers:
struct A {
struct B { double whatever; };
std::unordered_map<std::string, B> mapToB;
};
Edit: Here is a pointer alternative if the above doesn't meet your use case.
struct A {
double whatever;
std::unordered_map<std::string, std::unique_ptr<A>> mapToMoreA;
};
You can also just use boost::unordered_map which not only supports incomplete types but also has far greater debug performance in Visual Studio as Microsoft's implementation of std::unordered_map is incredibly inefficient due to excessive iterator debugging checks. I am unaware of any performance concerns on gcc for either container.
Boost.Variant has a handy utility explicitly for this purpose – boost::recusive_wrapper<>. The following should work:
struct A {
double whatever;
std::unordered_map<std::string, boost::recursive_wrapper<A>> mapToMoreA;
};
The only notable drawback is that Boost.Variant has not yet been updated to support C++11 move semantics. Update: added in Boost 1.56.
If having the map hold pointers isn't acceptable, perhaps this will work for you:
struct A {
struct hidden;
std::unique_ptr<hidden> pimpl;
};
struct A::hidden {
double whatever;
std::unordered_map<std::string, A> mapToMoreA;
};
In C++ you usually use pointers, which have predefined constant size, for incomplete types:
This of course changes how you use the map: you'll have to dereference with the * or -> operators to access members and have to delete the pointers at some point.
struct A
{
double bla;
std::map<std::string, A*> mapToMoreA;
};
Member functions of A should be split into a prototype inside the struct block and implemented later, otherwise A and its members are not yet completely defined:
struct A
{
double bla;
std::map<std::string, A*> mapToMoreA;
void doStuff(const std::string& str);
};
void A::doStuff(const std::string& str)
{
mapToMoreA[str] = new A();
}
Or use a pointer to the map. The pointer must be of type void* in this case (can be hidden behind a set of functions). Maybe there are alternatives to std::unordered_map that can cope with incomplete value types.
I think you can just forward declare struct A; prior to its definition and the compiler should be happy.
EDIT: So after being downvoted several times, I wrote the following to see what I was missing:
#include <boost/unordered_map.hpp>
#include <string>
#include <iostream>
struct A;
struct A {
double whatever;
boost::unordered_map<std::string, A> mapToMoreA;
};
int main(void)
{
A b;
b.whatever = 2.5;
b.mapToMoreA["abc"] = b;
std::cerr << b.mapToMoreA["abc"].whatever << std::endl;
return 0;
}
This compiles fine using g++ 4.2.1 on my mac, and prints out "2.5" when it's run (as expected).
Sorry that I don't have unordered_map without boost. Is that the issue? (i.e., does std::unordered_map somehow place more constraints on the compiler than boost does?) Otherwise, I'm not sure what I'm missing here about the question. Those downvoting this, please enlighten me with comments. Thanks!
I have class Base and classes Derived_1, Derived_2 ...
I need derived classes to have an id. Those ids are used for further lookups etc, and thus need to be consecutive (no just some random numbers). Because derived classes are created by user, id can not be member of Derived_N. So I came up with DerivedType class.
class DerivedType
{
static unsigned id;
unsigned m_id;
public:
DerivedType() : m_id(id++) { }
}
Now I want to create a mapping between Derived_N and DerivedType.
Whenever Derived_N is created, this mapping looks if DerivedType for particular Derived_N already exist and returns it, otherwise create new and stores in the map.
Actual question:
Is there any way to use std::map with data type as key in the map?
I am not afraid of any template-metaprogram solution.
Or is there elegant way how to achieve my goal?
edit Date type -> Data type, I mean like ClassType, I am sorry :)
I want to use it like:
Derived_5 d;
DerivedType dt = getType(d); //Derived_5 is looked up in map, returning particular DerivedType
dt.getId();
every instance of Derived_N (with same 'N') should have the same id throu DerivedType
EDIT2 - MY ANSWER
I found better solution for my problem... It is like this:
atomic_counter s_nextEventClassID;
typedef int cid_t;
template<class EventClass>
class EventClassID
{
public:
static cid_t getID()
{
static cid_t classID = EventClassID::next();
return classID;
}
static cid_t next() { return ++s_nextEventClassID; }
};
since my question was how to use datatype in a map, I will mark some of yours answers, thank you
C++11 solves this by providing std::type_index, in <typeindex>, which is a copyable, comparable and hashable object constructed from a std::type_info object that can be used as the key in associative containers.
(The implementation is fairly simple, so even if you don't have C++11 yourself, you could steal the implementation from, say GCC 4.7, and use that in your own code.)
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
typedef std::unordered_map<std::type_index, int> tmap;
int main()
{
tmap m;
m[typeid(main)] = 12;
m[typeid(tmap)] = 15;
}
You can use typeid(object) directly, since there is type_info::before, which can be used as comparator if you use type_info as key in the map, see What is `type_info::before` useful for?. No need to get .name().
You can use whatever type or class you want as the key to std::map, provided you give the template arguments a compare function that tells it how to sort the underlying tree.
The easiest thing to do IMHO to represent dates as keys, is to convert them to unix timestamps, but no matter what the class representation of them may be, just provide a comparison function to the map's definition and you're good to go.
class A {}
A a;
type_info info = typeid (a); // error type_info is private
i want a list list<type_info> to store the type of classes. Is there a solution?
You can't create copies of 'type_info' objects. However, the result if 'typeid' is an Lvalue and the corresponding 'type_info' objects, once obtained, continue to live till the end of the program. For these reasons, you can safely store pointers to 'type_info' objects in your list.
You cannot instantiate objects of the type_info class directly, because the class has only a private copy constructor. Since the list needs copy constructor...
If you really need it, use std::list< type_info*>.
I don't know why you need this list, but I would think to an alternative design, not involving RTTI, if possible.
From your comment to Cătălin Pitiș' answer, I understand that your goal is to write a function that returns a different "Style" type for different "Page" types. Does this have to be dynamic? If not, would something like this do what you want?
template<class PageT>
struct StyleOf;
template<>
struct StyleOf<PageA>{
typedef StyleA type;
};
template<>
struct StyleOf<PageB>{
typedef StyleB type;
};
// etc...
template<class PageT>
typename StyleOf<PageT>::type
GetStyle(const PageT&){
return StyleOf<PageT>::type();
}
Or, with Boost.MPL:
using boost::mpl::map;
using boost::mpl::pair;
typedef map<
pair<PageA, StyleA>,
pair<PageB, StyleB>,
//etc.
>
PageToStyle;
Getting the Style type from the Page type is:
boost::mpl::at<PageToStyle, Page>::type;