I want to store data by both, their name and their index. In other words, I want to map string names to objects and also give them a custom order.
What I came up with first is a std::vector of pairs of the string key and the object. The order was given by the position in the vector.
std::vector<std::pair<std::string, object> >
But this approach seems to be suboptimal since it doesn't automatically check for the uniqueness of string names. Moreover it feels wrong to group the objects by their order first, because logically their first order distinction is the name.
I need a data structure that allows access by both name and index.
std::magic<std::string, unsigned int, object> collection;
// access by either string or unsigned int key
collection.insert("name", 42, new object());
collection["name"]
collection[42]
Is there a data structure for this use case already? If not, how can I put one together, preferably using the standard library? Also I would like a way to insert new elements at the position after a given element without moving all further elements around.
Boost provides a set of containers just for this purpose, see: boost::multiindex
I'm trying to write a solution using std library, as requested in the original post. I will not have access to boost in my resource-constrained system. I've drafted a two-map system mentioned in the comments.
A big downside is that you'll have to wrap each public function that a std::map or std::vector normally offers, and my wrapper might not be as optimal.
But, this is a start. Let me know of improvements to my answer in the comment, and I'll edit the response when I can
#include <unordered_map>
#include <string>
#include <iostream>
struct Object
{
int val;
};
template <typename T>
class MultiKeyMap
{
std::unordered_map<std::string, uint> nameToIdMap;
std::unordered_map<uint, T> idToValMap;
public:
T& find(const std::string& name)
{
return find(nameToIdMap[name]);
}
T& find(const uint id)
{
return idToValMap[id];
}
T& operator[](const std::string& name) { return find(name); }
T& operator[](const uint id) { return find(id); }
void insert(uint id, const std::string& name, T&& val)
{
nameToIdMap[name] = id;
idToValMap[id] = val;
}
};
int main()
{
MultiKeyMap<Object> mkmap;
mkmap.insert(1, "one", Object{11});
mkmap.insert(2, "two", Object{22});
std::cout << "key=1: val=" << mkmap[1].val << "\n";
std::cout << "key='one': val=" << mkmap["one"].val << "\n";
std::cout << "key=2: val=" << mkmap[2].val << "\n";
std::cout << "key='two': val=" << mkmap["two"].val << "\n";
}
Related
In short, I tried searching on how to do this, but I seem to be missing something. One constraint to my problem: Human.h cannot change. We must operate with what we've been given. I am also told to create the array of pointers to members to decide on which function needs to be called.
Here's what I have:
Human.h
class Human
{
private:
void meleeAttack(std::string const& target);
void rangedAttack(std::string const& target);
void intimidatingShout(std::string const& target);
public:
void action(std::string const& action_name, std::string const& target);
};
Human.cpp
#include "Human.h"
typedef void (Human::* Human_mem_fnPtr)(std::string target);
void Human::meleeAttack(std::string const& target)
{
std::cout << "Melee Attack performed on " << target << "!\n";
}
void Human::rangedAttack(std::string const& target)
{
std::cout << "Ranged Attack performed on " << target << "!\n";
}
void Human::intimidatingShout(std::string const& target)
{
std::cout << "Shout performed on " << target << "!\n";
}
void Human::action(std::string const& action_name, std::string const& target)
{
//error on initialization--expression must be an lvalue or function designation--but they ARE func designations...
Human_mem_fnPtr fnPtr[] = {&Human::meleeAttack(target), &Human::rangedAttack(target), &Human::intimidatingShout(target)};
}
From what I found online, I am going in the right direction here. What am I missing?
A couple of points:
Doing pointers to functions is made much easier with the std::function<> template class.
Using a old-style array is not really the best choice these days.
A map or unordered_map would be a much better option, with a definition like this:
using ActionMap = std::unordered_map<const std::string, std::function<void(const std::string&)>;
When adding your functions to this map you would use something like the following:
mActionMap["rangedAttack"] = std::mem_fn(&Human::rangedAttack);
This will give you a cleaner and easier to maintain option and should compile cleanly.
Note that the std::mem_fn is required to wrap a member function of a class.
Edit: Per your comment below, Id still suggest using as many of the modern C++ constructs as possible.
using ActionFunc = std::function<void(const std::string&)>;
And then:
ActionFunc actions[] = { std::mem_fn(&Human::rangedAttack), ...}
or:
std::array<ActionFunc> actions = ...
I want to have a map to save different types of value, so I have a map like
std::map<int, std::variant<int, std::string>> m ={{1,1},{2,"asd"}};
And Now I want to design a function to get the value by its key like
auto get(int key) {
...
return value;
}
That's to say what I want is like
get(1) -> 1
get(2) -> "asd"
So is it possible? If so what's the exact solution?
ADDED:
Yes, as for the purpose of the design, I want to save config datas reading from config files.
And after reading I need to make some type changing or data transform.
Such as in config files like
a=1
b=asd
And after reading it, I want to save it as
m["a"]=int(3) ---->refers a=1 and needs to plus 2 after reading its actual data 1
m["b"]=std::string("asdasd") ---->refers b=asd and needs to double it
So I think it will be easier if there is an interface function to get the exact value by the key
You cannot exactly design a function with this syntax. Just imagine this:
int key = 0;
if (rand() % 2) {
key = 1;
} else {
key = 2;
}
auto value = get(key);
Here's the riddle:
Please tell me the return type of get and the type of value. There can be only one answer and you can only answer with a single type that will remain unchanging no matter how much time I ask you this question.
If you can't answer, well, the compiler cannot either.
However, it doesn't mean you can't design something similar that will do what you need.
You could just return the variant. This might not be exactly what you're looking for, but it's worth noting since it doesn't change any of the input of the get function.
You can also just send the expected type:
get<int>(key)
The implementation would look like this:
template<typename T>
auto get(int key) -> T {
return std::get<int>(m[key]);
}
If you cannot know the expected type, then you could just send a visitor:
get(key, [](auto value) -> std::size_t {
if constexpr (std::same_as<int, decltype(value)>) {
// do stuff with value as an int since it's a int here
return value + 1;
} else {
// do stuff with value as a string since it's a string here
return value.size();
}
});
The implementation would look like this:
auto get(int key, auto visitor) -> decltype(auto) {
return std::visit(visitor, m[key]);
}
If I understand the requirements, you could return a proxy object from get that keeps a reference to the variant and depending on what you do with the proxy object, it can adapt. Example:
#include <iostream>
#include <variant>
#include <map>
#include <string>
struct Foo {
using variant = std::variant<int, std::string>;
// the proxy object
struct proxy {
// assignment:
template<class T>
variant& operator=(T&& value) {
*data = std::forward<T>(value);
return *data;
}
// for static_cast to the wanted type
explicit operator int& () { return std::get<int>(*data); }
explicit operator std::string& () { return std::get<std::string>(*data); }
variant* data;
};
proxy get(int key) {
// return the proxy object
return proxy{&m[key]};
}
std::map<int, std::variant<int, std::string>> m = {{1,1}, {2,"asd"}};
};
And it could be used like this:
int main() {
Foo f;
// you need to know what it stores:
std::cout << static_cast<int>(f.get(1)) << '\n';
std::cout << static_cast<std::string>(f.get(2)) << '\n';
// assigning is simple:
f.get(1) = "hello world"; // was int, now std::string
f.get(2) = 2; // was std::string, now int
std::cout << static_cast<std::string>(f.get(1)) << '\n';
std::cout << static_cast<int>(f.get(2)) << '\n';
}
Two possibilities:
A) You want to return either int or std::string depending on the index passed to the function.
Not possible. A function has one return type. Also auto is not magic. If you cannot write the actual type, then the compiler can't either.
B) You want to return the mapped_type of the map.
You can return std::variant<int, std::string> from the function.
Your get can't do much "better" than std::variant::get. With std::variant::get you need to specify at compile time what type you want to retrieve. And there is no way around that if you want to get either int or std::string.
There might be better ways to solve your actual issue, the one for which you thought auto get(int key) was the solution. A comment (by Eljay) mentions std::visit. There you can see a couple of examples of how to deal with variants.
Consider the following program, which is a minimal example trying to reproduce a problem with some legacy code:
#include <iostream>
#include <ext/hash_map>
// Define a hash for std::string class so we can use it as keys
// in hash_map below.
namespace __gnu_cxx {
template <>
struct hash<std::string> {
size_t operator() (const std::string& x) const {
return hash<const char*>()(x.c_str());
}
};
}
// Data class contains a string
class Data {
public:
std::string s;
Data() { s = "foobar"; }
Data(std::string s_) : s(s_) {}
};
// Map keyed by string. Values are Data instances
typedef __gnu_cxx::hash_map<std::string, Data> DataMap;
int main()
{
DataMap m;
std::string key = "test";
// I am storing a "Data" instance d, for "key". d.s is the same as key.
Data d = Data(key);
m[key] = d;
DataMap::iterator it = m.find(key);
if (it == m.end()) {
std::cerr << "not there " << std::endl;
return 1;
}
Data *dp = &it->second;
// Question about the following line. Is the behavior well-defined?
m.erase(dp->s);
return 0;
}
I am storing my class Data instances in a hash_map. I search for a particular data member using a key, and then erase that value using m.erase(dp->s). m.erase(dp->s) will delete the object pointed to by dp. Am I allowed to use dp->s in the call to erase(), or must I first make a copy and then erase():
std::string key_to_delete = dp->s;
m.erase(key_to_delete);
Looking at the implementation, it seems as if even after the node (the pair pointed to by it) is deleted, the key passed to the erase function is still referenced. If dp is deleted, then the reference to dp->s becomes invalid. Yet the implementation of hash_map is still trying to dereference it. Fail.
You would need to pass something that is guaranteed to stay valid for the call to erase.
You could
m.erase(key);
Or you can use the iterator returned by find to do the erase:
m.erase(it);
I am using a container to hold a list of pointers to anything:
struct Example {
std::vector<boost::any> elements;
}
To insert elements in this container, I had written a couple of helper functions (members of the struct Example):
void add_any(boost::any& a) {
elements.push_back(a);
}
template<typename T>
void add_to_list(T& a) {
boost::any bany = &a;
add_any(bany);
}
Now, I would like to insert elements only when they are not present in this container. To do this, I thought that I would only need to call search over elements with an appropriate comparator function. However, I do not know how to compare the boost::any instances.
My question:
Knowing that my boost::any instances always contain a pointer to something; is it possible to compare two boost::any values?
update
I thank you for your answers. I have also managed to do this in a probably unsafe way: using boost::unsafe_any_cast to obtain a void** and comparing the underlying pointer.
For the moment, this is working fine. I would, however, appreciate your comments: maybe this is a big mistake!
#include <boost/any.hpp>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
bool any_compare(const boost::any& a1, const boost::any& a2) {
cout << "compare " << *boost::unsafe_any_cast<void*>(&a1)
<< " with: " << *boost::unsafe_any_cast<void*>(&a2);
return (*boost::unsafe_any_cast<void*>(&a1)) ==
(*boost::unsafe_any_cast<void*>(&a2));
}
struct A {};
class Example {
public:
Example() : elements(0),
m_1(3.14),
m_2(42),
m_3("hello"),
m_4() {};
virtual ~Example() {};
void test_insert() {
add_to_list(m_1);
add_to_list(m_2);
add_to_list(m_3);
add_to_list(m_4);
add_to_list(m_1); // should not insert
add_to_list(m_2); // should not insert
add_to_list(m_3); // should not insert
add_to_list(m_4); // should not insert
};
template <typename T>
void add_to_list(T& a) {
boost::any bany = &a;
add_any(bany);
}
private:
vector<boost::any> elements;
double m_1;
int m_2;
string m_3;
A m_4;
void add_any(const boost::any& a) {
cout << "Trying to insert " << (*boost::unsafe_any_cast<void*>(&a)) << endl;
vector<boost::any>::const_iterator it;
for (it = elements.begin();
it != elements.end();
++it) {
if ( any_compare(a,*it) ) {
cout << " : not inserting, already in list" << endl;
return;
}
cout << endl;
}
cout << "Inserting " << (*boost::unsafe_any_cast<void*>(&a)) << endl;
elements.push_back(a);
};
};
int main(int argc, char *argv[]) {
Example ex;
ex.test_insert();
unsigned char c;
ex.add_to_list(c);
ex.add_to_list(c); // should not insert
return 0;
}
You cannot directly provide it, but you can actually use any as the underlying type... though for pointers it's pointless (ah!)
struct any {
std::type_info const& _info;
void* _address;
};
And a templated constructor:
template <typename T>
any::any(T* t):
_info(typeid(*t)),
_address(dynamic_cast<void*>(t))
{
}
This is, basically, boost::any.
Now we need to "augment" it with our comparison mechanism.
In order to do so, we'll "capture" the implementation of std::less.
typedef bool (*Comparer)(void*,void*);
template <typename T>
bool compare(void* lhs, void* rhs) const {
return std::less<T>()(*reinterpret_cast<T*>(lhs), *reinterpret_cast<T*>(rhs));
}
template <typename T>
Comparer make_comparer(T*) { return compare<T>; }
And augment the constructor of any.
struct any {
std::type_info const& _info;
void* _address;
Comparer _comparer;
};
template <typename T>
any::any(T* t):
_info(typeid(*t)),
_address(dynamic_cast<void*>(t)),
_comparer(make_comparer(t))
{
}
Then, we provided a specialization of less (or operator<)
bool operator<(any const& lhs, any const& rhs) {
if (lhs._info.before(rhs._info)) { return true; }
if (rhs._info.before(lhs._info)) { return false; }
return (*lhs._comparer)(lhs._address, rhs._address);
}
Note: encapsulation, etc... are left as an exercise to the reader
The only easy way to do this I can think of involves hardcoding support for the types that you're storing in the any instances, undermining much of the usefulness of any...
bool equal(const boost::any& lhs, const boost::any& rhs)
{
if (lhs.type() != rhs.type())
return false;
if (lhs.type() == typeid(std::string))
return any_cast<std::string>(lhs) == any_cast<std::string>(rhs);
if (lhs.type() == typeid(int))
return any_cast<int>(lhs) == any_cast<int>(rhs);
// ...
throw std::runtime_error("comparison of any unimplemented for type");
}
With C++11's type_index you could use a std::map or std::unordered_map keyed on std::type_index(some_boost_any_object.type()) - similar to what Alexandre suggests in his comment below.
If you can change type in container, there is Boost.TypeErasure. It provides easy way to customize any. For example I'm using such typedef for similar purpose:
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/operators.hpp>
using Foo = boost::type_erasure::any<
boost::mpl::vector<
boost::type_erasure::copy_constructible<>,
boost::type_erasure::equality_comparable<>,
boost::type_erasure::typeid_<>,
boost::type_erasure::relaxed
>
>;
Foo behaves exactly the same as boost::any, except that it can be compared for equality and use boost::type_erasure::any_cast instead of boost::any_cast.
There is no need to create new class. Try to use xany https://sourceforge.net/projects/extendableany/?source=directory xany class allows to add new methods to any's existing functionality. By the way there is a example in documentation which does exactly what you want (creates comparable_any).
Maybe this algorithm come in handy >
http://signmotion.blogspot.com/2011/12/boostany.html
Compare two any-values by type and content. Attempt convert string to number for equals.
I would like my classes to be identified each type by an unique hash code. But I don't want these hashed to be generated every time a method, eg. int GetHashCode(), is invoked during runtime. I'd like to use already generated constants and I was hoping there is a way to make the compiler do some come computing and set these constants. Can it be done using templates? Could you give me some example, if it is possible.
UPDATE:
Thanks to kriss' comment I realized my question should go like this:
How to do the type checking with the lowest runtime cost possible?
I'd like to check a pointer to an object against a class type. Just the classes I implement in my libs, so I was thinking of some custom hashing, thus the original question. I did consider using typeid but I am unaware of the runtime cost of using it. I made an assumption that since typeid produces a type_info class that would be more consuming than simple comparision of unique int values.
You can do it with boost.MPL.
I would go simple route:
For classes that would be static property - so just pick a number for each class.
For instances - just use the address.
Static const's are evaluated at compile time - which is pretty much the basis for metaprogramming at large. Moreover, type_info::hash_code is particularly adapted for your needs, so try -
class MyClass
{
static const size_t TypeHashCode = typeid(MyClass).hash_code();
...
}
(I'm not around a compiler right now, so this may take some refining. Will try and recheck tomorrow)
EDIT: indeed, it is not only MS specific but also added only in VS2010 - but hey, at least MS agrees this is a valid need. If you don't allow both VS2010 and boost in your code - you're pretty much left with the standard compliant facilities: typeid or dynamic_cast. They do incur some overhead, but I'd take extra care to verify this overhead is indeed a worthy battle. (my money goes to - not.)
All such classes share something common. Then why not add a symbolic constant in a common enum for each one, you'll leave the enum give values for you, it's easier than giving explicit constants (you still have to declare each class in the enum).
template<class T>
struct provide_hash_code_for_class
{
public:
static uintptr_t GetHashCode()
{
return(reinterpret_cast<uintptr_t>(&unused));
}
private:
static void *unused;
};
template<class T>
void *provide_hash_code_for_class<T>::unused;
class MyClass : public provide_hash_code_for_class<MyClass>
{
};
int main()
{
std::cout << std::hex << MyClass::GetHashCode() << std::endl;
std::cout << std::hex << MyClass().GetHashCode() << std::endl;
return(0);
}
Please be aware that hash codes will change between runs so you can't rely on them for example for interprocess communication.
building on the simple route route by Nikolai N Fetissov:
For classes that would be static property - use the address of a function cast to an intptr_t to give a unique yet compiled-in value.
For instances - just use the address.
It is a pitty that there is no compile-time type hash_code supported by the standard. As a workaround, one can generate a compile time hash from the class name. An example below.
#include <stdint.h>
#include <string>
#include <vector>
#include <iostream>
#include <memory>
#include <cassert>
//Compile-time string hashing.
class HashedString
{
public:
typedef int64_t HashType;
explicit constexpr HashedString(const char* str): m_hash(hashString(str)) {}
static inline constexpr HashType hashString(const char* str)
{
return ( !str ? 0 : hashStringRecursive(5381, str));
}
static inline constexpr HashType hashStringRecursive(HashType hash, const char* str)
{
return ( !*str ? hash : hashStringRecursive(((hash << 5) + hash) + *str, str + 1));
}
const HashType m_hash;
};
struct EventBase
{
using IdType = HashedString::HashType;
virtual ~EventBase() {}
IdType getId() const { return m_eventId; } //present the runtime event id
EventBase(IdType myId) : m_eventId { myId } { }
template<class DerivedEvent>
const DerivedEvent* getAs() const
{
return dynamic_cast<const DerivedEvent*>(this);
}
protected:
const IdType m_eventId;
};
#define DEFINE_EVENT_ID(className) \
static constexpr IdType id = HashedString(#className).m_hash; \
struct SomeEvent1 : public EventBase
{
DEFINE_EVENT_ID(SomeEvent1);
SomeEvent1(int status) : EventBase(id), m_status { status } { assert(id == m_eventId); }
int m_status;
};
struct SomeEvent2 : public EventBase
{
DEFINE_EVENT_ID(SomeEvent2);
SomeEvent2() : EventBase(id) { assert(id == m_eventId); }
std::string m_s = "test event 2";
};
void testEvents()
{
std::vector<std::shared_ptr<EventBase>> events;
events.push_back(std::make_shared<SomeEvent1>(123));
events.push_back(std::make_shared<SomeEvent2>());
for (auto event : events) {
switch(event->getId()) {
case SomeEvent1::id:
std::cout << "SomeEvent1 " << event->getAs<SomeEvent1>()->m_status << std::endl;
break;
case SomeEvent2::id:
std::cout << "SomeEvent2 " << event->getAs<SomeEvent2>()->m_s << std::endl;
break;
}
}
}