what is the best way to share different objects between some classes in a generic manner?
For example class A can store an object o with a string as a key in a register and class B can access it using the key.
My first idea was to create a register (singleton) which has a hashtable as a member using a string as the key and a void pointer as the value. But there must be a better solution for this?
From your clarification:
template <typename OB>
class A {
std::unordered_map<std::string, OB> hash;
public:
OB const& get(std::string const&) const;
void add(OB const& object, std::string const&);
};
That is to say, A<int> is a class that stores int objects by name, and A<std::set<float>> is a class that stores sets of floats by name. You can't mix them. That's in line with the basic C++ philosophy: the type of theA.get("foo") is determined at compile time, not by what you put in at runtime.
In C++, you can however "mix" multiple derived types, if you'd need this for your particular case. That's a bit more complicated:
template <typename Base>
class A {
std::unordered_map<std::string, std::unique_ptr<Base>> hash;
public:
Base const& get(std::string const&) const;
template<typename Derived> void add(std::string const& name, Derived const& object)
{
std::unique_ptr<Base> copy(new Derived(object));
hash.emplace(std::make_pair(name, std::move(copy)));
}
};
There's some slight trickery here as hash should be the only owner of the copy, but it's constructed outside and therefore needs to be moved it. (For extra-fancy, I could add a Derived&& overload that eliminates that copy too)
I would suggest that all the classes that you must register have a common supertype.
For instance, if you have to store instances of classes One, Two, and Three you could define a (possibly empty) class Object from which your class can derive:
class Object {}
class One : public Object { /* One's member and methods */ }
class Two : public Object { /* Two's member and methods */ }
class Three : public Object { /* Three's member and methods */ }
If you follow MSalters question you can then declare a A<Object*>.
If you cannot have one supertype (for instance because you cannot change One, Two or Three) you may look at Boost.Variant. Again, you can declare a A<boost::variant<One, Two, Three> >.
The first question is: how does B know the type of the stored object,
and what it can do with it? Perhaps the simplest solution is just to
have one registry per type. Alternatively, something like
boost::variant can be used, or you can ensure that all types derive
from a common base, and store a pointer to that. Unless you actually
need to support polymorphism (e.g. operating on an object without
knowing its exact type), I'd avoid the pointer solution, however.
The best way is to use a shared_ptr, instead of a naked pointer. If you have a C++11 compliant compiler, shared_ptr is in the std namespace. Otherwise, use the Boost implementation.
Related
There is a templated class, let it be
template<typename T> class A { std::vector<T> data; };
The problem I am facing here is, users can create several types of this class, but I need to track them, best case is I have a reference of these objects in another vector, but that would not work since all types are different.
Can you recommend a good design pattern which can encapsulate this.
I can store pointers and then typecast it, but its not elegant.
I can change the architecture as well, if the solution provided is good enough.
The basic question I am trying to solve is, I have a class of vector of custom types, how do I store them.
As previous comments stated - you first need to make sure this is what you need.
With that been said, I had a similar requirement in a project of mine, which I eventually solved with inheritance and PIMPL, as follows:
class A{
private:
struct Abstract {
virtual void f() = 0;
};
template <typename T>
struct Implementation : public Abstract {
std::vector<T> data;
virtual void f() {...}
};
std::unique_ptr<Abstract> impl;
public:
template <typename T>
A(): impl(std::make_unique<Implementation<T> >()){}
void f() {impl->f();}
};
This allows you to create a container of objects of type A, and access them via the public interface defined therein (the method f). The underlying type T of each A object is specified on construction. All other implementation details specific to the type T are hidden.
The solution suffers the inherent overhead of virtual functions. I'm not sure how it compares to the std::any approach performance-wise.
std::any is the modern c++17 solution. Specifically, you should use
A<int> a;
a.data.push_back(0);
// fill refernces...
std::vector<std::any> refernces;
refernces.push_back(&a.data[0]);
// check which type is active.
if(int** iPtr = std::any_cast<int*>(&references[0]); iPtr != nullptr)
{
// its an int*
int& i = **iPtr;
// do something with i.
}
These pointers can point into the A<int>::data and A<double>::data vectors.
For a complete reference, see here https://en.cppreference.com/w/cpp/utility/any.
Disclaimer: I am afraid the short answer to my question is "not possible". But since I am not a C++ expert, I thought I still give it a try and ask here, maybe there is some kind of solution which I am just not aware of.
So I have templated container-like class MyContainer that internally stores data in a std::list<T>, where T is the class template type. This works fine.
Now I want to add another class, which has to map instances of that templated container class in a std::map<std::string, MyContainer>. However, the compiler asks me to provide the template class type for the value-part of the map, as in std::map<std::string, MyContainer<T>>. But I would rather omit this template here, since that would in turn require me to use templates for the wrapper class as well.
Thus my question: Is there a way to achieve what I am trying to do, omitting the template type for the wrapper class, at least to some extend? Or is this just not possible in C++, because the compiler needs that information in any case?
One common technique for doing this is inheritance.
You make MyContainer<T> inherit from some base class, such as MyBaseContainer. MyBaseContainer is not a template class, but MyContainer is. The MyBaseContainer class has virtual functions that the templated class overrides.
Then, you make your map of type std::map<std::string, MyBaseContainer*>. It will be able to call the virtual functions on the containers it stores, without having to know the template type of each one.
This is how std::function works.
This is possible but a bit tricky. If i understand you correctly you want each MyContainer class stored inside map to possibly have different template specialization (say some will hold std::list<int> while other will hold std::list<string>) then you value type for map can no longer be just MyContainer but rather class that could hold both list<int> and list<string>.
One way to do it to use inheritance as #IanPudney already pointed out.
However you can do this even without creating inheritance hierarchy for MyContainer classes if you instead declare map as map<string, boost::any> (see http://www.boost.org/doc/libs/1_61_0/doc/html/boost/any.html) that way you will be able to store any kind of MyContainer inside this map without the need to create inheritance hierarchy in advance.
There are two possible ways to do this without using inheritance but this may also depend on a few deciding factors. The first question is: Upon creating an instance of the outside class is the type of the template container known. If it is then this is an easy class to write. If it is not then it can still be done but there would be more work involved. If case is not known there are 2 ways to do this and the first is the one you are trying to avoid by not making this a class template. The second involves more work which some of the logic on how to define this class will be shown.
Pseudo Code: -- 1st Case Where Type Is Known Upon Creation
#include <map>
template<class T>
class MyContainer {
// ... Class Variables, Constructors & Methods
}
// For Demonstration We will say that `T` is known to be an int upon instantiation
class MyClass {
private:
std::map< std::string, MyContainer<int> > maps_;
public:
MyClass() {}
~MyClass() {
// Clear Out Map
}
void addItem( std::string& str, int value ) {
maps_.insert( std::make_pair( str, MyContainer<int>( value ) );
}
};
Now for the 2nd case where the type is not known using the method without templating the wrapper you will need to know of all of the types that this class can support and you will need to create typedef of each of these.
Pseudo Code -- 2nd Case Where Type Is Not Known:
#include <map>
template<class T>
class MyContainer {
// ... Class Variables, Constructors & Methods
}
// For Demonstration We will say that `T` is unknown before instantiation
class MyClass {
public:
typedef MyContainer<int> INTS;
typedef MyContainer<float> FLOATS;
typedef MyContainer<double> DOUBLES;
// And Do This For Every Type This Class Will Support.
private:
std::map< std::string, INTS > mapInts_;
std::map< std::string, FLOATS > mapFloats_;
std::map< std::string, DOUBLES > mapDoubles_;
// And You Will Need A Container For Each Supporting Type
public:
MyClass() {}
// If You Have Constructors Other Than Default That Excepts Parameter Types
// You Will Need A Constructor For Each Supporting Type
~MyClass() {
// Clear Out All Maps
}
void addInts( std::string& str, MyClass::INTS );
void addFloats( std::string& str, MyClass::FLOATS );
void addDoubles( std::string& str, MyClass::DOUBLES );
// And You Will Need A Corresponding Function For Each Type This Class Supports.
};
I am trying to write a class that I can store and use type information in without the need for a template parameter.
I want to write something like this:
class Example
{
public:
template<typename T>
Example(T* ptr)
: ptr(ptr)
{
// typedef T EnclosedType; I want this be a avaialable at the class level.
}
void operator()()
{
if(ptr == NULL)
return;
(*(EnclosedType*)ptr)(); // so i can cast the pointer and call the () operator if the class has one.
}
private:
void* ptr;
}
I am not asking how to write an is_functor() class.
I want to know how to get type information in a constructor and store it at the class level. If that is impossible, a different solution to this would be appreciated.
I consider this as a good and valid question, however, there is no general solution beside using a template parameter at the class level. What you tried to achieve in your question -- using a typedef inside a function and then access this in the whole class -- is not possible.
Type erasure
Only if you impose certain restrictions onto your constructor parameters, there are some alternatives. In this respect, here is an example of type erasure where the operator() of some given object is stored inside a std::function<void()> variable.
struct A
{
template<typename T>
A(T const& t) : f (std::bind(&T::operator(), t)) {}
void operator()() const
{
f();
}
std::function<void()> f;
};
struct B
{
void operator()() const
{
std::cout<<"hello"<<std::endl;
}
};
int main()
{
A(B{}).operator()(); //prints "hello"
}
DEMO
Note, however, the assumptions underlying this approach: one assumes that all passed objects have an operator of a given signature (here void operator()) which is stored inside a std::function<void()> (with respect to storing the member-function, see here).
Inheritance
In a sense, type erasure is thus like "inheriting without a base class" -- one could instead use a common base class for all constructor parameter classes with a virtual bracket operator, and then pass a base class pointer to your constructor.
struct A_parameter_base
{
void operator()() const = 0;
};
struct B : public A_parameter_base
{
void operator()() const { std::cout<<"hello"<<std::endl; }
};
struct A
{
A(std::shared_ptr<A_parameter_base> _p) : p(_p) {}
void operator()()
{
p->operator();
}
std::shared_ptr<A_parameter_base> p;
}
That is similar to the code in your question, only that it does not use a void-pointer but a pointer to a specific base class.
Both approaches, type erasure and inheritance, are similar in their applications, but type erasure might be more convenient as one gets rid of a common base class. However, the inheritance approach has the further advantage that you can restore the original object via multiple dispatch
This also shows the limitations of both approaches. If your operator would not be void but instead would return some unknown varying type, you cannot use the above approach but have to use templates. The inheritance parallel is: you cannot have a virtual function template.
The practical answer is to store either a copy of your class, or a std::ref wrapped pseudo-reference to your class, in a std::function<void()>.
std::function type erases things it stores down to 3 concepts: copy, destroy and invoke with a fixed signature. (also, cast-back-to-original-type and typeid, more obscurely)
What it does is it remembers, at construction, how to do these operations to the passed in type, and stores a copy in a way it can perform those operations on it, then forgets everything else about the type.
You cannot remember everything about a type this way. But almost any operation with a fixed signature, or which can be intermediaried via a fixed signature operation, can be type erased down to.
The first typical way to do this are to create a private pure interface with those operations, then create a template implementation (templated on the type passed to the ctor) that implements each operation for that particular type. The class that does the type erasure then stores a (smart) pointer to the private interface, and forwards its public operations to it.
A second typical way is to store a void*, or a buffer of char, and a set of pointers to functions that implement the operations. The pointers to functions can be either stored locally in the type erasing class, or stored in a helper struct that is created statically for each type erased, and a pointer to the helper struct is stored in the type erasing class. The first way to store the function pointers is like C-style object properties: the second is like a manual vtable.
In any case, the function pointers usually take one (or more) void* and know how to cast them back to the right type. They are created in the ctor that knows the type, either as instances of a template function, or as local stateless lambdas, or the same indirectly.
You could even do a hybrid of the two: static pimpl instance pointers taking a void* or whatever.
Often using std::function is enough, manually writing type erasure is hard to get right compared to using std::function.
Another version to the first two answers we have here - that's closer to your current code:
class A{
public:
virtual void operator()=0;
};
template<class T>
class B: public A{
public:
B(T*t):ptr(t){}
virtual void operator(){(*ptr)();}
T*ptr;
};
class Example
{
public:
template<typename T>
Example(T* ptr)
: a(new B<T>(ptr))
{
// typedef T EnclosedType; I want this be a avaialable at the class level.
}
void operator()()
{
if(!a)
return;
(*a)();
}
private:
std::unique_ptr<A> a;
}
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.
I have a class that has the following variables/members:
First Name
Last Name
Age
Address
etc..
I want to create getter-methods for each of them that returns the values. This could become quite large depending on the class.
Is there a quicker or more object-oriented way that would allow me to do this just using one method? The only way I can think about is to have a method that takes a parameter of the name of the variable to be returned; however, the types for the method would change depending on if it was returning a string, int etc..
Does anyone have a solution?
Why do you need those values outside the class? If you have code that is not in Person that calls 4 or 5 Person GetWhatever() methods and glues the strings together, stuffs commas between them and so on, move that code into Person. Do that enough and no code outside Person needs to call your getters.
Some classes are logic-free, they just hold values, and they expect outside objects to do all the work. In C++, using a struct for that makes your intention clear. If you insist that code outside Person needs to arbitrarily access elements of Person, it's probably a struct, not a class. If you insist it's a class, prove it by adding some actual business logic to it.
No, there is no "better" way which is still object-oriented. You should define one public "getter" method for each private member variable which needs to be access outside the class. You should also define a setter method, if the variable is meant to be set from outside the class.
If you want easy to define setter/getter - make it on single member level. Make member template with setter/getter and define is as public element of your class:
template <class Type>
class Member {
public:
Member(const T& value = T()) : value(value) {}
void setValue(const Type& t) { value = t; }
T getValue() const { return value; }
private:
T value;
};
Use it in your class:
class Person {
public:
Member<std::string> firstName;
Member<std::string> lastName;
Member<std::string> address;
Member<unsigned> age;
};
And usage:
int main() {
Person one;
one.firstName.setValue("Joe");
one.age.setValue(33);
}
If your need some constraints (like range checking) then define some RangeCheckingMember template. If you need the members to be dependent on each others - then make relationship between them by pointers/references.
Consider making that parameter lookup using a template member function that takes a default value in a given type.
template<typename ValueType>
const ValueType& get(const KeyType& key, const ValueType& default value) {
...
};
You still have to enumerate (or otherwise list) a KeyType of all your values (or use std::string which might be fine in larger cases) and work back and forth with your storage on the ValueType.
So, this doesn't really help you much until you decide you need arbitrarily large or completely dynamic values. At this point, you need to implement a map which can hold any type which requires either hideous unions or a template wrapper derived class from a common base class used in the map.
The upside to this is that a getKeys() method can present all of the keys available in the class -- something quite useful for dynamic GUIs and message handling.
If you are using a library in which everything subclasses some Object class (QObject for example), you can use a map of (string, object) to hold all your data and then access it with:
Object get(string name) { return memebers[name]; }
members is std::map<std::string, Object>
You will need to use type casts of course.
Button* my_var = static_cast<Button*>(my_class.get("my_button"));
// get returns Object
You can also use Qt's property system if you use Qt. This is not standard c++, but qmake and moc work on many operating systems.
all right.since you know what you want.
void get(int flag, void *return_value)
get the return_value typd casting to what you want.
thanks