Accessing Values in a Class Similar to boost::any - c++

I'm making a simple boost::any-like class for educational purposes, but I can't figure out how to access the stored value. I can set the value perfectly, but when I try to access any member in the "holder" class the compiler just complains that the member wasn't found in the class it was derived from. I can't declare the members as virtual because of the templates.
Here's the relevant code:
class Element
{
struct ValueStorageBase
{
};
template <typename Datatype>
struct ValueStorage: public ValueStorageBase
{
Datatype Value;
ValueStorage(Datatype InitialValue)
{
Value = InitialValue;
}
};
ValueStorageBase* StoredValue;
public:
template <typename Datatype>
Element(Datatype InitialValue)
{
StoredValue = new ValueStorage<Datatype>(InitialValue);
}
template <typename Datatype>
Datatype Get()
{
return StoredValue->Value; // Error: "struct Element::ValueStorageBase" has no member named "Value."
}
};

It's fine to add virtual functions to templates- just the functions themselves cannot be templates. A templated class or struct can still have virtual functions just fine. You need to use the magic of dynamic_cast.
class Element
{
struct ValueStorageBase
{
virtual ~ValueStorageBase() {}
};
template <typename Datatype>
struct ValueStorage: public ValueStorageBase
{
Datatype Value;
ValueStorage(Datatype InitialValue)
{
Value = InitialValue;
}
};
ValueStorageBase* StoredValue;
public:
template <typename Datatype>
Element(Datatype InitialValue)
{
StoredValue = new ValueStorage<Datatype>(InitialValue);
}
template <typename Datatype>
Datatype Get()
{
if(ValueStorage<DataType>* ptr = dynamic_cast<ValueStorage<DataType>*>(StoredValue)) {
return ptr->Value;
else
throw std::runtime_error("Incorrect type!"); // Error: "struct Element::ValueStorageBase" has no member named "Value."
}
};
If you change Get to return a Datatype* you can return NULL instead of throwing. You also haven't handled the memory of the previous value of StoredValue, but I'm leaving that up to you.

You need to cast it to ValueStorage first.
Also add virtual destructur to ValueStorageBase class, to have polymorphic class. Without it you can't runtime check if your casting is OK :).
After it you can write:
template <typename Datatype>
Datatype Element_cast()
{
//throw exception for a wrong cast
if(typeid(*StoredValue)!=typeid(ValueStorage<Datatype>) )
throw exception;
//we already checked, that our type casting is OK,
//So no need for dynamic_cast anymore
return static_cast<ValueStorage*> (StoredValue)->value;
}

Related

Declare new function inside a class using a template

I'm still learning about templates. I'm not sure whether you can declare/(automatically define) a function inside a class (method) using a template. That is, I have a function template defined like this, for example:
template<typename T>
T getT() {
T result;
return result;
}
And a class, where I want the "new function" to be created, based on the template, like this:
class World{
public:
World();
~World();
getT<int>; //"Magically" create new function from the template (return type 'int')
}
What I actually want is to have only a method with the specific given type in World. That means when I want to "magically" create a method based on the template, I want to sort of copy-paste the template function into the class but with the given type.
For example:
class World{
public:
World();
~World();
//The magically created function with T equal to int
int getT(){
int result;
return result;
}
}
Then of course I expect to be able to call the function:
int main(){
World world; //Create world object
world.getT<int>; //Call the function
return 0;
}
Even though here I say I would call it with getT<int>, it could be only getT() (if it is a perfect copy-paste of the template function).
Be carfull
template<typename T>
T& getT() {
T result;
return result;
}
Will return a reference to a temporary. Please do
template<typename T>
T getT() {
T result;
return result;
}
without "&"
And if it's just for get a specific member, you can use std::tuple.
https://en.cppreference.com/w/cpp/utility/tuple/get
getT<int>; //"Magically" create new function from the template (return type 'int')
I don't think that will work.
It appears as though you would like to be able to use templates like macro expansion. Unfortunately, they are very different things and templates don't work like macro expansion.
However, you can use something like the following:
template<typename T>
struct GetHelper
{
T get()
{
return T{};
}
};
class World : private GetHelper<int>,
private GetHelper<double>
{
public:
World() {}
~World() {}
template <typename T>
get()
{
return static_cast<GetHelper<T>*>(this)->get();
}
};
Now you can use:
World w;
int a = w.get<int>();
double b = w.get<double>();
You may also hide GetHelper as a private type of World as:
class World
{
private:
template<typename T>
struct GetHelper
{
T get()
{
return T{};
}
};
struct Data : GetHelper<int>,
GetHelper<double>{};
Data data;
public:
World() {}
~World() {}
template <typename T>
get()
{
return static_cast<GetHelper<T>*>(&data)->get();
}
};

How to define an embedded class's method that returns an enum hack outside the outer class?

I am trying to implement a class vec which looks like class vector everything is ok until I tried to defined an embedded class method that returns an enum hack value outside the Outer class.
Here is my interface:
#define MAX 1000
template <class T>
class vec{
public:
// ctors, dtor, oper. over...
// Exeption handling
class CExcep {
public:
virtual void what()const = 0;
};
class COutBound : public CExcep {
public:
enum RANGE_ERROR {
NEGATIVE, TOO_BIG
};
COutBound(const int, const RANGE_ERROR);
const int getIndex()const;// { return index};
const RANGE_ERROR getError()const;// { return or ; }
virtual void what()const;
private:
const int index;
const RANGE_ERROR or;
};
private:
// some member data here
};
Above I embedded the CExcep base class inside my class vec and I used inheritance to use catch easily to catch exceptions through a base class reference.
I didn't provide implementation for the sake of brevity.
So The problem:
How can I define COutBound::getError outside class vec?
To do something like that COutBound::getIndex I managed to do that:
// ok
template<class T>
const int vec<T>::COutBound::getIndex()const{
return index;
}
But:
// Error here?
template<class T>
const vec<T>::COutBound::RANGE_ERROR
vec<T>::COutBound::getError()const{
return or;
}
Simply getError returns an enum hack value of type RANGE_ERROR. If I define it inside the interface it is ok. But I want to do that outside. (separate interface from implementation).
You need to use typename for RANGE_ERROR because it is a dependent type:
template<class T>
typename vec<T>::COutBound::RANGE_ERROR
vec<T>::COutBound::getError()const{
return or;
}
or C++ 11 trailing return:
template<class T> auto
vec<T>::COutBound::getError()const -> RANGE_ERROR {
return orx;
}
Also const qualifiers on simple return types are not useful and or is a reserved operator name.

Why can I not static_cast a templated object down an inheritance tree?

To be short:
Derived inherits from Base
Holder is templated to contains a pointer to anything
I can tell that an object know as Holder<Base> is a Holder<Derived>.
How can I tell my compiler?
This does not compile:
struct Base { };
struct Derived : Base { };
template <typename T>
struct Holder {
T* point;
int id;
};
Derived* d = new Derived();
Holder<Base> holder {d, 12};
Holder<Derived> specific( static_cast<Holder<Derived>>(holder) );
error: no matching conversion for static_cast from 'Holder<Base>' to 'Holder<Derived>'
This was a naive try for sure. But why does this not work and how should I get the specific holder I need?
Because Holder<Derived> is not derived from Holder<Base>, they are completely unrelated types that just happen to be generated from the same class template.
You can create a Holder<Derived> that contains the right value:
Holder<Derived> specific{ static_cast<Derived*>(holder.point), holder.id };
Or you could add that functionality to the Holder class template itself by adding a converting constructor that does the cast:
template <typename T>
struct Holder {
Holder(T* pt, int id) : point(pt), id(id) { }
template<typename U>
Holder(const Holder<U>& h)
: point(static_cast<T*>(h.point)), id(h.id)
{ }
T* point;
int id;
};
Now your original attempt to use static_cast will work, because there is a valid conversion between them, or you can just write it as:
Holder<Derived> specific( holder );
That statement will compile as long as static_cast<Derived*>(holder.point) compiles.

C++ templating syntax - allocate type with pointer

How can I do memory allocation like this:
template <class T>
class A
{
T Generate()
{
return new T(); // Error
}
};
A<B *> a;
B * pI = A.Generate();
Or can you only ever define something as:
A<B> a;
If I understood you correctly you wish to have specialization of A for pointer types. Try something like:
#include <cstdio>
template <class T>
class A
{
public:
T *Generate()
{
printf("A\n");
return new T; // Error
}
};
template <class T>
class A<T*> {
public:
T *Generate() {
printf("Specialization of A\n");
return new T;
}
};
class B {
};
int main() {
A<B *> a;
B * pI = a.Generate();
}
Edit:
To "override" only a part of the functionality:
template <class T>
class Generator
{
public:
T *Generate()
{
printf("Generator\n");
return new T; // Error
}
};
template <class T>
class Generator<T*> {
public:
T *Generate() {
printf("Specialization of Generator\n");
return new T;
}
};
template <class T>
class A: public Generator<T>
{
public:
// does some other stuff
};
You have a bunch of issues with your code:
A.Generate() should be a.Generate() as Generate is a member function.
new T() returns T*, so your Generate function should look like:
T* Generate()
{
return new T();
}
This should also be reflected in your usage:
A<B *> a;
B ** pI = a.Generate(); //generator for B* returns B**
new will return a pointer so you need the signature
T* Generate()
{
return new T();
}
This function must also be public if you'd like to call it outside the class.
How can I do memory allocation like this
By fixing the syntax and semantic errors.
Return type of Generate is T, yet you return T*. You probably want to change the return type to T*. Accordingly, you must assign the returned type to a T* variable. Since your T is B*, that variable must have the type B**.
You try to call a non-static member of A without an instance. Call the member using the instance instead. Also, that member is private. Make it public.
When you've fixed the code, you'll see that it does memory allocation successfully.
Or can you only ever define something as:
A<B> a;
No, there are many more ways to define something.

A pointer to abstract template base class?

I cannot figure this out. I need to have an abstract template base class, which
is the following:
template <class T> class Dendrite
{
public:
Dendrite()
{
}
virtual ~Dendrite()
{
}
virtual void Get(std::vector<T> &o) = 0;
protected:
std::vector<T> _data;
};
Now, I derive from this which specifies exact usage of Dendrite.
Now the problem.
How do I create a vector of pointers to the base-class with no specific type, which
I want to specify by pushing elements to it later? Something like:
class Foo
{
public:
...
private:
std::vector<Dendrite *> _inputs; //!< Unfortunately, this doesn't work...
//! Now I could later on push elements to this vector like
//!
//! _inputs.push_back(new DeriveFromDendrite<double>()) and
//! _inputs.push_back(new DeriveFromDendrite<int>()).
};
Is this possible or am I missing something very basic here?
Typically this is done by your template inheriting from an interface class, IE:
template <class T> class Dendrite : public IDendrite
{
public:
Dendrite()
{
}
virtual ~Dendrite()
{
}
void Get(std::vector<T> &o) = 0;
protected:
std::vector<T> _data;
};
and then you're IDendrite class could be stored as pointers:
std::vector<IDendrite*> m_dendriteVec;
However, in your situation, you are taking the template parameter as part of your interface. You may also need to wrap this also.
class IVectorParam
{
}
template <class T>
class CVectorParam : public IVectorParam
{
std::vector<T> m_vect;
}
giving you
class IDendrite
{
...
public:
virtual ~IDendrite()
virtual void Get(IVectorParam*) = 0;
}
template <class T> class Dendrite : public IDendrite
{
...
// my get has to downcast to o CVectorParam<T>
virtual void Get(IVectorParam*);
};
Yes it is possible. Just make sure to provide virtual functions, and virtual destructor. In addition, you can use typeid to get the actual type (as well as dynamic_cast to check the type)