map<Key,pair<A,B>> to map<Key,A> - c++

I have a class that for some reasons needs to store a pair (say int,double) for each key, but whose interface only makes public one of the two values of the pair (int). One implementation may be
using namespace std;
class Foo {
public:
map<string,int> const & get() const {return external;}
void doStuff(string const & str) {
external.at(str);
internal.at(str);
}
private:
map<string,int> external;
map<string,double> internal;
};
The drawback is that doStuff has double lookup.
Another way is to store map<string,pair<int,double>> allin but then the accessor returning the whole map requires a copy.
The last way, of course, is to make the accessor more atomic by accessing a single key with a return allin.at(key).first;, which seems the best way but it breaks the interface I would like to provide.
I wonder, is there a way to avoid the double lookup in the "external/internal" version?

Another way could be to define a map entry with a private and a public value. Via a friend declaration the private value can be made visable to Foo class.
#include <iostream>
#include <string>
#include <map>
class Foo;
template<typename T1, typename T2>
struct my_map_entry
{
public:
my_map_entry()=default;
my_map_entry(T1 v, T2 pv)
{
value = v;
private_value = pv;
}
T1 value;
private:
T2 private_value;
friend class Foo;
};
class Foo {
public:
Foo(){
map["test"]=my_map_entry<int, double>(1, 2.0);
}
void doStuff(const std::string& str
{
auto entry = map.at(str);
std::cout<<"private_value: "<<entry.private_value<<std::endl;
}
std::map<std::string,my_map_entry<int, double>> map;
};
int main()
{
Foo test;
test.doStuff("test");
}

Given you just want the user to be able to retrieve the item, your get() method can be rewritten bearing that requirement in mind.
using namespace std;
class Foo {
public:
int *const get(string const &str) const {
auto it = map_.find(str)
return it == map_.end() ? nullptr : &it->first;
}
void doStuff(string const & str) {
map_.at(str);
}
private:
map<string,pair<int, double>> map_;
};
The idea is to return nullptr if the key was not found, or a pointer to the value if the key was found.
If instead you also want to be able to enumerate all the available ints, then you only have three choices:
Make your Foo class a map-like class, with its own iterators that wrap the ones from the inner map.
Use one of the available libraries to provide a view that helps you achieving the previous goal (like boost::transform_iterator)
As the other answer suggests, use a struct as the map's value and make one of its fields private, with possibly a conversion operator to int.

Related

unique container for template class

I have an algorithm (not preseted here) which takes as input different parameters (int, float, vectors).
My idea of design was to have an container which holds all these differents parameters.
To achive this, I have a base class Parameter and a derivated template class TypeParameter.
These parameters will be holded in a container.
The design is presented below:
#pragma once
#include <utility>
#include <memory>
#include <string>
#include <vector>
namespace parameter
{
/*
Interface for parameter
*/
class Parameter
{
public:
Parameter() {}
Parameter(std::string param_name) : name(param_name) {}
Parameter(const Parameter&& other) noexcept : name(std::move(other.name)) {}
virtual ~Parameter() {}
inline const std::string get_name() { return name; }
private:
std::string name;
};
/*
*/
template<class T>
class TypeParameter
: public Parameter
{
public:
TypeParameter(std::string param_name, T new_value) : Parameter(param_name), value(new_value) {}
TypeParameter(const TypeParameter&& other) noexcept : Parameter(std::move(other)), value(std::move(other.T)) {}
inline const T get_value() { return value; }
private:
T value;
};
/*
Container for parameters
*/
class ParameterSet
{
public:
ParameterSet() {}
void add(std::unique_ptr<Parameter> param) { data.push_back(std::move(param)); }
private:
std::vector <std::unique_ptr<Parameter>> data;
};
} //namespace parameter
The main is:
#include <iostream>
#include <string>
#include "Parameter.h"
using parameter::TypeParameter;
using parameter::Parameter;
using parameter::ParameterSet;
void foo(std::unique_ptr<Parameter> p)
{
std::cout << p->get_value(); // ERROR
}
int main(int argc, char *argv[])
{
TypeParameter<int> *iparam = new TypeParameter<int>("ee", 3);
std::unique_ptr<Parameter> p = std::make_unique <TypeParameter<int>>("foo", 3);
foo(std::move(p));
ParameterSet param_set;
param_set.add(std::unique_ptr<Parameter>(iparam));
param_set.add(std::move(p));
getchar();
}
My problem is I cannot get the value without a cast.
Hence, my question is how do I cast the unique_ptr from a Parameter class to derived TypeParameter.
Is there another way to design the container?
Thanks a lot!
You don't have to reinvent the wheel. There are a couple of classes you can use from the standard library:
std::variant.
As suggested by the comments, variant is a type-safe union of a pre-defined set of data types, which you put in the templates argument of variant.
For example, a std::variant<int,float,double> can hold any value of type int, float, or double, but nothing else.
To use the stored value, you can either use the visitor pattern with the std::visit() function. Other functions allow you to know which of the preset types is stored in the variable (index()) and to extract the value from it (using get()). If you try to extract the value of the wrong type, the get() function throws an exception
std::any
is another utility that can hold different data types. As opposed to variant, you don't have to know the types at compile-time. Basically, it stores a void* to the data with a typeinfo to remember its original type. You can then use any_cast to cast the variable back to its original type. Just like variant, an exception is thrown when trying to cast to the wrong type.
These two classes are available in C++ 17. If these features are not available to you, they were also included in boost (respectively boost:variant and boost:any)
You can store the set of values in a standard library container, e.g. in a std::vector<std::variant<int,float,double>> or a std::vector<std::any>>.
Alternative to std::variant/std::any is the old way polymorphism:
class Parameter
{
public:
Parameter(const std::string& param_name) : name(param_name) {}
virtual ~Parameter() = default;
const std::string& get_name() const { return name; }
virtual void printValue() const = 0;
// Other virtual methods
private:
std::string name;
};
template<class T>
class TypeParameter : public Parameter
{
public:
TypeParameter(const std::string& name, const T& t) : Parameter(name), value(t) {}
// Non virtual method when we don't access it by base class.
const T& get_value() const { return value; }
void printValue() const { std::cout << value; }
private:
T value;
};
And then your
void foo(const Parameter& p)
{
std::cout << p.get_value(); // ERROR
}
becomes
void foo(const Parameter& p)
{
p.print();
}
If you don't want to add many virtual methods to Parameter, then Visitor pattern can help, but then you have to know each derived types.

Using template struct in vector with deffrent types

Hello this my c++ source
template <typename T>
struct Key
{
string Name;
T Value;
};
struct Block
{
string Name;
vector <Key> Keys; // I got error here ... !!!!
};
int main()
{
Block thisBlock;
Key <bool> Key1;
Key <string> Key2;
// Set key 1
Key1.Name = "Key1";
Key1.Value = false;
// Set key 2
Key2.Name = "Key2";
Key2.Value = "Hey";
// Set block with all keys
thisBlock.Name = "Block1";
thisBlock.Keys.push_back(Key1);
thisBlock.Keys.push_back(Key2);
return 0;
}
please guide me about this error ! i know i have to use <> in vector <Key> but if i do this, my block keys is limit to that type only ! is there any way to fix this problem?
Error
argument list for class template "Key" is missing (in block struct (vector <key>>)
Key<bool> and Key<string> are two different types, unrelated one to another, so, you cannot store both of them in one std::vector, just like you cannot create a std::vector storing both int and float.
To solve this issue, you could create a common base class for your keys, something like this:
class KeyBase {
public:
virtual ~KeyBase() = default; // virtual destructor to avoid memory leaks
std::string GetName() const { return name; }// some common functions
virtual std::string ToString() const = 0; // and some function to be overriden
std::string name; // and members
KeyBase(std::string name_) : name(name_) {};
KeyBase() = default;
};
template<class T>
class Key : public KeyBase {
public:
std::string ToString() const override { ... } // implementation of virtual functions
T value;
};
...
std::vector<std::unique_ptr<KeyBase>> vk;
vk.push_back(std::make_unique<Key<bool>>());
vk.push_back(std::make_unique<Key<string>>());
std::cout << vk[0]->GetName() << ' ' << vk[1]->GetName(); // Works
std::cout << vk[0]->value << ' ' << vk[1]->value; // Does not work as KeyBase has no value
std::cout << dynamic_cast<Key<bool>*>(vk[0].get())->value; // Works as vk[0] is now casted
std::unique_ptr used here is a smart pointer type - it's semantics are just like the pointer, but it deletes the storing object when is deleted, making memory management much easier. Also it's important here that the std::vector stores pointer to KeyBase, and not KeyBase. This is done to avoid object slicing.
Also, please use std::dynamic_cast with caution: it will return nullptr if you try to cast to an incorrect type.
UP: To set the value during the push_back operation, one way is to use the helper function and setting constructor:
template<typename T>
class Key : public KeyBase {
...
Key(T val) : value(val) {}
Key(T val, std::string name) : KeyBase(name), value(val) {}
}
template<typename T>
std::unique_ptr<Key<T>> createKey(T value) {
return std::make_unique<Key<T>>(value);
}
template<typename T>
std::unique_ptr<Key<T>> createKey(T value, std::string name) {
return std::make_unique<Key<T>>(value, name);
}
...
vk.push_back(createKey<bool>(false));
vk.push_back(createKey<string>("abc"));
Actually, with such approach you could even omit the type name, like this:
vk.push_back(createKey(1, "abc")); // creates Key<int> with value 1 and name "abc"
But be extra careful with such omission, for example, "abc" has type const char* and so createKey("abc") will create Key<const char*>.
If Block is to use a generic Key, you must make it a template as well:
template <typename T>
struct Block
{
string Name;
vector <Key <T>> Keys;
};
Addressing the more general problem, i.e. that you want to store objects of different type in the same vector, will require something like std::any or std::variant:
struct Block
{
std::string Name;
std::vector <std::variant<bool, std::string>> Keys;
};
For pre-C++17, the Boost libraries have boost::variant and boost::any which do the same thing.

C++ Template : one list by class, how to factorize the code?

Suppose I have this class :
class Component1;
class Component2;
// many different Components
class Component42;
class MyClass
{
public:
MyClass(void) {};
std::list<Component1> component1List;
std::list<Component2> component2List;
// one list by component
std::list<Component42> component42List;
};
I would like to create a function with the following signature:
template<class T> void addElement(T component);
It should do the following:
if component is of type Component1, add it to Component1List
if component is of type Component2, add it to Component2List, etc.
Is it possible? What's a good way to do this?
I can obtain the same behaviour with a function like :
template<class T> void addElement(int componentType, T component);
but I'd rather not have to specify the componentType like this : it's useless information and it open the door to possible errors (if componentType doesn't represent the type of component).
std::tuple to the rescue.
changelog:
use std::decay_t
added the variadic argument form
add_component() now returns a reference to this to allow call-chaining.
#include <iostream>
#include <list>
#include <utility>
#include <type_traits>
#include <tuple>
class Component1 {};
class Component2 {};
struct Component3 {
Component3() {}
};
// many different Components
template<class...ComponentTypes>
class MyClassImpl
{
template<class Component> using list_of = std::list<Component>;
public:
using all_lists_type =
std::tuple<
list_of<ComponentTypes> ...
>;
// add a single component
template<class Component>
MyClassImpl& add_component(Component&& c)
{
list_for<Component>().push_back(std::forward<Component>(c));
return *this;
}
// add any number of components
template<class...Components>
MyClassImpl& add_components(Components&&... c)
{
using expand = int[];
void(expand { 0, (void(add_component(std::forward<Components>(c))), 0)... });
return *this;
}
template<class Component>
auto& list_for()
{
using component_type = std::decay_t<Component>;
return std::get<list_of<component_type>>(_lists);
}
template<class Component>
const auto& list_for() const
{
using component_type = std::decay_t<Component>;
return std::get<list_of<component_type>>(_lists);
}
private:
all_lists_type _lists;
};
using MyClass = MyClassImpl<Component1, Component2, Component3>;
int main()
{
MyClass c;
c.add_component(Component1());
c.add_component(Component2());
const Component3 c3;
c.add_component(c3);
c.add_components(Component1(),
Component2(),
Component3()).add_components(Component3()).add_components(Component1(),
Component2());
std::cout << c.list_for<Component1>().size() << std::endl;
return 0;
}
The most straightforward variant is to simply not use templates but to overload the addElement() function:
void addElement(Component1 element)
{
this->element1List.push_back(element);
}
void addElement(Component2 element)
{
this->element2List.push_back(element);
}
// ... etc
However, this might get tedious if you have many of these (and you don't just have addElement(), I guess). Using a macro to generate the code for each type could still do the job with reasonable effort.
If you really want to use templates, you could use a template function and specialize the template function for each type. Still, this doesn't reduce the amount of code repetition when compared with the above approach. Also, you could still reduce it using macros to generate the code.
However, there's hope for doing this in a generic way. Firstly, let's create a type that holds the list:
template<typename T>
struct ComponentContainer
{
list<T> componentList;
};
Now, the derived class just inherits from this class and uses C++ type system to locate the correct container baseclass:
class MyClass:
ComponentContainer<Component1>,
ComponentContainer<Component2>,
ComponentContainer<Component3>
{
public:
template<typename T>
void addElement(T value)
{
ComponentContainer<T>& container = *this;
container.componentList.push_back(value);
}
}
Notes here:
This uses private inheritance, which is very similar to the containment you originally used.
Even though ComponentContainer is a baseclass, it doesn't have any virtual functions and not even a virtual destructor. Yes, this is dangerous and should be documented clearly. I wouldn't add a virtual destructor though, because of the overhead it has and because it shouldn't be needed.
You could drop the intermediate container altogether and derive from list<T>, too. I didn't because it will make all of list's memberfunctions available in class MyClass (even if not publicly), which might be confusing.
You can't put the addElement() function into the base class template to avoid the template in the derived class. The simple reason is that the different baseclasses are scanned in order for a addElement() function and only then overload resolution is performed. The compiler will only find the addElement() in the first baseclass therefore.
This is a plain C++98 solution, for C++11 I'd look at the type-based tuple lookup solutions suggested by Jens and Richard.
If there are not too many classes you could go with overloading. A template-based solution could be done with type-based lookup for tuples:
class MyClass {
public:
template<typename T> void addElement(T&& x) {
auto& l = std::get<std::list<T>>(lists);
l.insert( std::forward<T>(x) );
}
private:
std::tuple< std::list<Component1>, std::list<Component2> > lists;
};
If you don't know in advance the types you will need storing when instantiating the multi-container an option is to hide the types and using type_index to keep a map of lists:
struct Container {
struct Entry {
void *list;
std::function<void *(void*)> copier;
std::function<void(void *)> deleter;
};
std::map<std::type_index, Entry> entries;
template<typename T>
std::list<T>& list() {
Entry& e = entries[std::type_index(typeid(T))];
if (!e.list) {
e.list = new std::list<T>;
e.deleter = [](void *list){ delete ((std::list<T> *)list); };
e.copier = [](void *list){ return new std::list<T>(*((std::list<T> *)list)); };
}
return *((std::list<T> *)e.list);
}
~Container() {
for (auto& i : entries) i.second.deleter(i.second.list);
}
Container(const Container& other) {
// Not exception safe... se note
for (auto& i : other.entries) {
entries[i.first] = { i.second.copier(i.second.list),
i.second.copier,
i.second.deleter };
}
};
void swap(Container& other) { std::swap(entries, other.entries); }
Container& operator=(const Container& other) {
Container(other).swap(*this);
return *this;
};
Container() { }
};
that can be used as:
Container c;
c.list<int>().push_back(10);
c.list<int>().push_back(20);
c.list<double>().push_back(3.14);
NOTE: the copy constructor as written now is not exception safe because in case a copier throws (because of an out of memory or because a copy constructor of an element inside a list throws) the already allocated lists will not be deallocated.
void addElement(Component1 component) {
componentList1.insert(component);
}
void addElement(Component2 component) {
componentList2.insert(component);
}

Iterator Class Design in C++

I am trying to learn the concept of writing a generic iterator in C++. I came across this example given below. I don't understand the use of having NameCollection::value_type here. Why can't we have
Iterator<value_type> since its a templated class.
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
class Iterator {
public:
typedef T value_type;
virtual bool hasNext() = 0;
virtual T next() = 0;
};
class NameManager {
typedef vector<string> NameCollection;
NameCollection m_names;
public:
class NameIterator: public Iterator< NameCollection::value_type > {
friend class NameManager;
private:
NameManager::NameCollection & m_names;
NameManager::NameCollection::iterator m_itr;
NameIterator(NameManager::NameCollection & names) : m_names(names), m_itr(m_names.begin()) {}
public:
virtual bool hasNext() {
return m_itr!=m_names.end();
}
virtual NameIterator::value_type next(void) {
NameIterator::value_type value = (*m_itr);
++m_itr;
return value;
}
};
void addName(NameCollection::value_type name){
m_names.push_back(name);
}
NameIterator getNameIterator(void) {
return NameIterator(m_names);
}
};
int main(void) {
NameManager nameMgr;
nameMgr.addName("Jobs");
nameMgr.addName("Bill");
nameMgr.addName("Larry");
NameManager::NameIterator nameItr = nameMgr.getNameIterator();
while(nameItr.hasNext()) {
cout<<nameItr.next() << endl;
}
return 0;
}
Imagine you are writing generic code which should be able to work with any (or at least generic) iterators. Think about something from the <algorithm>. Such a code might be interested in the type of value (type of the expression *it). So value_type typedef is a standard interface to pass around this information.
NameCollection::value_type is std::string, of course. It can serve the same purpose: assume you want to change your underplaying container to use wide strings, or something else. Now if you use std::string explicitely, you will have to find and replace it everywhere. If you use NameCollection::value_type only one line has to be changed.
You can use it in the function 'next' as well (it will work), but semantically it makes much more sense to use iterator there, since this function is all about iterators.

C++ Push Multiple Types onto Vector

Note: I know similar questions to this have been asked on SO before, but I did not find them helpful or very clear.
Second note: For the scope of this project/assignment, I'm trying to avoid third party libraries, such as Boost.
I am trying to see if there is a way I can have a single vector hold multiple types, in each of its indices. For example, say I have the following code sample:
vector<something magical to hold various types> vec;
int x = 3;
string hi = "Hello World";
MyStruct s = {3, "Hi", 4.01};
vec.push_back(x);
vec.push_back(hi);
vec.push_back(s);
I've heard vector<void*> could work, but then it gets tricky with memory allocation and then there is always the possibility that certain portions in nearby memory could be unintentionally overridden if a value inserted into a certain index is larger than expected.
In my actual application, I know what possible types may be inserted into a vector, but these types do not all derive from the same super class, and there is no guarantee that all of these types will be pushed onto the vector or in what order.
Is there a way that I can safely accomplish the objective I demonstrated in my code sample?
Thank you for your time.
The objects hold by the std::vector<T> need to be of a homogenous type. If you need to put objects of different type into one vector you need somehow erase their type and make them all look similar. You could use the moral equivalent of boost::any or boost::variant<...>. The idea of boost::any is to encapsulate a type hierarchy, storing a pointer to the base but pointing to a templatized derived. A very rough and incomplete outline looks something like this:
#include <algorithm>
#include <iostream>
class any
{
private:
struct base {
virtual ~base() {}
virtual base* clone() const = 0;
};
template <typename T>
struct data: base {
data(T const& value): value_(value) {}
base* clone() const { return new data<T>(*this); }
T value_;
};
base* ptr_;
public:
template <typename T> any(T const& value): ptr_(new data<T>(value)) {}
any(any const& other): ptr_(other.ptr_->clone()) {}
any& operator= (any const& other) {
any(other).swap(*this);
return *this;
}
~any() { delete this->ptr_; }
void swap(any& other) { std::swap(this->ptr_, other.ptr_); }
template <typename T>
T& get() {
return dynamic_cast<data<T>&>(*this->ptr_).value_;
}
};
int main()
{
any a0(17);
any a1(3.14);
try { a0.get<double>(); } catch (...) {}
a0 = a1;
std::cout << a0.get<double>() << "\n";
}
As suggested you can use various forms of unions, variants, etc. Depending on what you want to do with your stored objects, external polymorphism could do exactly what you want, if you can define all necessary operations in a base class interface.
Here's an example if all we want to do is print the objects to the console:
#include <iostream>
#include <string>
#include <vector>
#include <memory>
class any_type
{
public:
virtual ~any_type() {}
virtual void print() = 0;
};
template <class T>
class concrete_type : public any_type
{
public:
concrete_type(const T& value) : value_(value)
{}
virtual void print()
{
std::cout << value_ << '\n';
}
private:
T value_;
};
int main()
{
std::vector<std::unique_ptr<any_type>> v(2);
v[0].reset(new concrete_type<int>(99));
v[1].reset(new concrete_type<std::string>("Bottles of Beer"));
for(size_t x = 0; x < 2; ++x)
{
v[x]->print();
}
return 0;
}
In order to do that, you'll definitely need a wrapper class to somehow conceal the type information of your objects from the vector.
It's probably also good to have this class throw an exception when you try to get Type-A back when you have previously stored a Type-B into it.
Here is part of the Holder class from one of my projects. You can probably start from here.
Note: due to the use of unrestricted unions, this only works in C++11. More information about this can be found here: What are Unrestricted Unions proposed in C++11?
class Holder {
public:
enum Type {
BOOL,
INT,
STRING,
// Other types you want to store into vector.
};
template<typename T>
Holder (Type type, T val);
~Holder () {
// You want to properly destroy
// union members below that have non-trivial constructors
}
operator bool () const {
if (type_ != BOOL) {
throw SomeException();
}
return impl_.bool_;
}
// Do the same for other operators
// Or maybe use templates?
private:
union Impl {
bool bool_;
int int_;
string string_;
Impl() { new(&string_) string; }
} impl_;
Type type_;
// Other stuff.
};