Value to type runtime mapping - c++

Consider this code
enum Types
{
t1,
t2
};
struct Base
{
Types typeTag;
Base(Types t) : typeTag(t){}
};
template<typename T>
struct Derived : Base
{
using Base::Base;
T makeT() { return T(); }
};
int main()
{
Base *b = new Derived<std::string>(t1);
auto d = getDerivedByTag(b); // How ??
d->makeT();
return 0;
}
Is it possible to restore Derived type parameter by Base::typeTag value in runtime? Obviously, some external preliminarily prepared mapping is needed, but I can't figure out the exact way.

What you want is basically a reflection that is not (yet) supported in C++. There are ways to simulate it or work around it but they are often verbose and not elegant. I would suggest rethinking your design, particularly your use of auto. It is not supposed to substitute for "any type" as you seem to imply by your code. It is meant as simplification of code when actual type is long or obfuscated (often happens with templates), nested etc. Not when you do not know the type! Because then you cannot really use it, can you.
So what you will have to do in one way or another is check the typeTag directly and continue based on that information. Alternatively you would need to use polymorphism using the Base directly (calling virtual methods propagated to Derived). For type unions you could use boost::variant (if you do not care what type Derived template argument is) or some other framework/library alternative like QVariant in Qt.

I'm not sure if my understanding is correct.
#include "iostream"
enum Types
{
t1,
t2
};
template<typename T>
struct Base
{
typedef T DerivedType;
Types typeTag;
Base(Types t) : typeTag(t){}
DerivedType* operator()() {
return static_cast<DerivedType*>(this);
}
};
template<typename T>
struct Derived : Base<Derived<T>>
{
Derived(Types t): Base<Derived<T>>(t) {}
T makeT() { return T(); }
};
int main()
{
Base<Derived<std::string>> *b = new Derived<std::string>(t1);
auto d = (*b)();
d->makeT();
return 0;
}
https://godbolt.org/g/uBsFD8
My implementation has nothing to do with typeTag.
Do you mean getDerivedByTag(b->typeTag) rather than getDerivedByTag(b)?

Related

Create a templated variable within a templated class of a different type

I'm not sure what I am asking for is possible.
I have a templated class called Controller. This is a variadic template class which takes multiple classes and can set their values as such.
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32);
This takes a bunch of different classes together and allows me to to set their values at the same time. setValues is a templated function which allows any type to be passed in. However, right now I am trying to modify my class so that I can set a value within the controller itself for easy retrieval. However this is the part that is proving difficult.
template<typename...Classes>
class Controller
{
public:
Controller(Classes&...objects) : objects(objects...){}
Controller(std::tuple<Classes&...> tup) : objects(tup){}
template<typename T>
void setValues(T value)
{
std::apply([&](auto&...x) { x.updateValue(value),...);}, objects); //calls the updateValue function for each class
}
private:
std::tuple<Classes&...> objects;
};
I want to add the following as a private variable T controllerValue; However, I know that I cannot simply declare T because we cannot define member templates and the compiler has no idea what to expect. Which then I tried to create a private struct:
template<typename T>
struct ControllerValue { T value; };
However, I cannot define a struct underneath that, because the same problem occurs. The compiler has no idea what type ControllerValue is. What I would like is something like this:
template<typename...Classes>
class Controller
{
public:
Controller(Classes&...objects) : objects(objects...){}
Controller(std::tuple<Classes&...> tup) : objects(tup){}
template<typename T>
void setValues(T value)
{
thisValue.value = value;
std::apply([&](auto&...x) { x.updateValue(value),...);}, objects); //calls the updateValue function for each class
}
template<typename T>
T getValue() const { return thisValue.value }
private:
std::tuple<Classes&...> objects;
template<typename T>
struct ControllerValue { T value; };
ControllerValue thisValue;
};
This will not compile at all for the same reason that the compiler has no idea what type ControllerValue should be. And this is where I am stuck. Is this even possible to do? If not, what is another way that I can make this work?
To clear up confusion, the use case would be something like this:
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32);
int commonValue = myController->getValue();
or
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32.3);
double commonValue = myController->getValue();
I think solving this exact problem is impossible in C++ (and still very cumbersome in languages with runtime generics). You can very easily create a polymorphic class that can only store any value:
class PolymorphicBase
{
public:
virtual ~PolymorphicBase() = default;
};
template <class T>
class PolymorphicObject : public PolymorphicBase
{
T value;
public:
PolymorphicObject(T value) : value(std::move(value))
{
}
};
A member of std::unique_ptr<PolymorphicBase> can sufficiently store any value, but how would such a value be retrieved? Probably the easiest is to expose the reference to PolymorphicBase and use dynamic type checks to see if the type is compatible with something you know, but what if you need the code to work for any type?
This is what lambdas with auto parameters are useful for. However, you would have to be able to pass such a lambda to a method on PolymorphicBase and implement that method in PolymorphicObject. This is impossible, since you cannot override a method template (it needs to be a template to accept a lambda) – that's where the compile-time and runtime parts of C++ clash. And there is simply no type in C++ that represents a function accepting any parameter (and knowing its type), which is a template by itself.
You can partially solve this by making the type of the lambda known to PolymorphicBase:
template <class Retriever>
class PolymorphicBase
{
public:
virtual void retrieve(Retriever func) = 0;
virtual ~PolymorphicBase() = default;
};
template <class Retriever, class T>
class PolymorphicObject : public PolymorphicBase<Retriever>
{
T value;
public:
PolymorphicObject(T value) : value(std::move(value))
{
}
void retrieve(Retriever func) override
{
func(value);
}
};
auto lambda = [](auto arg)
{
std::cout << arg << std::endl;
};
PolymorphicObject<decltype(lambda), int> obj(6);
PolymorphicBase<decltype(lambda)> &ptr = obj;
ptr.retrieve(lambda);
This is useful if you ever have only a single way to retrieve the value.
I don't think this is needed in most cases anyway. Usually you use a fixed set of types as the values, so you can use a variant there, or they all implement a common interface, or (as you've pointed out in the comments) you actually meant to move the type parameter from the method to the class (which allows you to check that all the types actually support the value earlier than originally).
However, I agree that in languages with generics/templates it is somewhat hard to have a method that can actually choose its result type in a generic fashion, without being controlled by outside parameters.

Is such a downcast safe?

Suppose we have the following code:
#include <memory>
#include <vector>
struct BaseComponent
{
template <typename T>
T * as()
{
return static_cast<T*>(this);
}
virtual ~BaseComponent() {}
};
template <typename T>
struct Component : public BaseComponent
{
virtual ~Component() {}
};
struct PositionComponent : public Component<PositionComponent>
{
float x, y, z;
virtual ~PositionComponent() {}
};
int main()
{
std::vector<std::unique_ptr<BaseComponent>> mComponents;
mComponents.emplace_back(new PositionComponent);
auto *pos = mComponents[0]->as<PositionComponent>();
pos->x = 1337;
return 0;
}
In the T * as() method, should I use a static_cast or a dynamic_cast? are there times when the the conversion will fail? Do I need to dynamic_cast like this instead?
auto *ptr = dynamic_cast<T*>(this);
if(ptr == nullptr)
throw std::runtime_error("D'oh!");
return ptr;
In your case there is no way to tell statically whether this is the right type or not.
What you may want is a CRTP (Curiously recurring template pattern):
template <class T>
struct BaseComponent
{
T* as()
{
return static_cast<T*>(this);
}
virtual ~BaseComponent() {}
};
template <typename T>
struct Component : public BaseComponent<T>
{
virtual ~Component() {}
};
struct PositionComponent : public Component<PositionComponent>
{
float x, y, z;
virtual ~PositionComponent() {}
};
This way you can do:
auto x = yourBaseComponent.as();
and have the right child type statically.
The code that you present is correct and well formed, but the cast in general is not safe. If the actual object was not a PositionComponent, then the compiler would very gladly assume that it is and you would be causing undefined behavior.
If you replace the cast with dynamic_cast, then the compiler will generate code that at runtime verifies that the conversion is valid.
The real question is why would you need this. There are reasons, but more often than not the use of casts are an indication of issues with your design. Reconsider whether you can do better (i.e. redesign your code so that you don't need to go explicitly converting types)
Since you are using unique_ptr<BaseComponent>, naturally there could be times when the conversion fails: the insertion of new data in the vector and consumption of that data are done in unrelated places, and in such a way that the compiler cannot enforce it.
Here is an example of an invalid cast:
struct AnotherComponent : public Component<AnotherComponent>
{
virtual ~AnotherComponent () {}
};
std::vector<std::unique_ptr<BaseComponent>> mComponents;
mComponents.emplace_back(new AnotherComponent);
// !!! This code compiles, but it is fundamentally broken !!!
auto *pos = mComponents[0]->as<PositionComponent>();
pos->x = 1337;
In this respect, using dynamic_cast would provide better protection against incorrect usage of the as<T> function. Note that the incorrect usage may not be intentional: any time the compiler cannot check the type for you, and you have a potential type mismatch, you should prefer dynamic_cast<T>
Here is a small demo to illustrate how dynamic_cast would offer you a degree of protection.
You should always use dynamic_cast when casting polymorphic objects that are derived from a baseclass.
In a case where mComponents[0] is not PositionComponent (or a class derived therefrom), the above code would fail. Since the whole purpose of having mComponents hold a pointer to BaseComponent is so that you can put other things than PositionComponent objects into the vector, I'd say you need to care for that particular scenario.
In general, it's a "bad smell" when you are using dynamic_cast (or generally casting objects that are derived from a common baseclass). Typically it means the objects should not be held in a common container, because they are not closely enough related.

C++ making a template class as place holder in another class

I am trying to make a template class as placeholder class which can hold something like and string and type T object. Below is the code which I have written for the same.
#include <iostream>
#include <string>
#include <map>
using namespace std;
//A class which act as placeholder to hold
//unknown object. Something similar as Object
//in Java
template <typename T>
class Genric
{
public:
map<string, T> addP; //This will be placeholder for time
// being.
};
class A
{
public:
Genric t1; //Have object of Genric class so that we can
// access the member variable in future.
void foo()
{
cout<<"Calling foo"<<endl;
}
};
int main()
{
A a1;
a1.foo();
}
But when I tried to compile I am getting below error.
$ g++ tempClass.cxx
tempClass.cxx:21:9: error: invalid use of template-name 'Genric' without an argument list
The purpose of above Genric class is just to act as placeholder class for one of the member variables which can be populated in future.
So is there a way we can write such Genric class.
You are defining Genric as a template class, but then trying to initialize t1 without giving a type to it. That is the error you are getting. Try for example:
Genric<int> t1;
Or, if you are looking for a truly runtime generic, look into boost::any.
You need something like boost::any:
map<string, boost::any> anywayzz;
You can store any object in it. You don't need Genric class template.
If you're not using boost, then you can implement any yourself. Look for its implementation, or type-erasure, on this site. You will surely get some idea. Start from here:
Type erasure techniques
A template is "generic" until the program is compiled. At that point the compile must be made aware of what types it has to deal with.
If you want something that can contain a compile-time unknown (better: not yet known) type template are not the solution. Since the actual type will be known just at runtime, you have to go towards runtime-based polymorphism (inheritance from a polymorphic base) eventually wrapped inside an "handler".
In essence you need a base with at leas t a virtual function that allow you to check the type, and generic derived class that implement that function in a suitable way for all types.
boost::any can be an implementation, but there can be simpler ways, especially considering that "a function that allows to discover a runtime type" is no more than ... dynamic_cast.
You can so cometo a solution like this
#include <memory>
class any_value
{
template<class T>
class wrapper; //see below
class common_base
{
public:
virtual ~common_base() {} //this makes the type polymorphic
template<class T>
T* has_value()
{
auto* ptr = dynamic_cast<wrapper<T>*>(this);
return ptr? &ptr->m: nullptr;
}
};
template<class T>
class wrapper: public common_base
{
public:
wrapper() :m() {}
wrapper(const T& t) :m(t) {}
T m;
};
std::unique_ptr<common_base> pb;
public:
any_value() {}
template<class T>
any_value(const T& t) :pb(new wrapper<T>(t)) {}
template<class T>
any_value& operator=(const T& t)
{ pb = std::unique_ptr<common_base>(new wrapper<T>(t)); return *this; }
any_value(any_value&&) =default;
any_value& operator=(any_value&&) =default;
//NOW THE GETTERS
template<class T>
T* get() const //nullptr if not holding a T*
{ return bool(pb)? pb->has_value<T>(): nullptr; }
template<class T>
bool get(T& t)
{
T* pt = get<T>();
if(pt) t = *pt;
return bool(pt);
}
};
#include <iostream>
#include <string>
int main()
{
any_value a(5), b(2.7192818), c(std::string("as a string"));
int vi=0; double vd=0; std::string vs;
if(!a.get(vi)) vi=0; //will go
if(!a.get(vd)) vd=0; //will fail
if(!a.get(vs)) vs.clear(); //will fail
std::cout <<"vi = "<<vi<<", vd = "<<vd<<", vs = "<<vs<<" \n";
if(!b.get(vi)) vi=0; //will fail
if(!b.get(vd)) vd=0; //will go
if(!b.get(vs)) vs.clear(); //will fail
std::cout <<"vi = "<<vi<<", vd = "<<vd<<", vs = "<<vs<<" \n";
if(!c.get(vi)) vi=0; //will fail
if(!c.get(vd)) vd=0; //will fail
if(!c.get(vs)) vs.clear(); //will go
std::cout <<"vi = "<<vi<<", vd = "<<vd<<", vs = "<<vs<<" \n";
}
Following Abhinav comment:
Since the C++ type system is static, you cannot -in general- deserialize an "unknown", unless you first deserialize something that can be "Known".
For this you first need a way to represet a C++ type (not object) into an recognizable value (sort of type-uid), and a "factory" that creates the wrappers appropriated for those "values".
On saving, you just save that uid, then ask via a common_base virtual function to save the wrapped value.
On loading, you first load the uid, than create a new wrapper with appropriate type (see after) and than load the value via a common_base virtual function.
To create an appropriate wrapper, you need a table that maps the uid-s towards functions that create the wrapper associated with the type uid.
This table must be pre-initialized for all the types you need to be able to serialize / deserialize.
But this goes long away your original question, that doesn't speak about serialization/deserialization.
If the problem is "serialization", the "type erasure" is not a complete solution. You should much more look at the "factory pattern". And post another question better suited for that argument.

Constructor Template

I have a class with several constructors. According to a parameter which is passed via argv to main() I would like to switch between the different constructors. The following simplified example works fine in the case where "obj" is changed to class and I use e.g. obj1->int and obj2->double. But what do I have to change to make the following code run using enum?
#include<iostream>
using namespace std;
enum obj{obj1,obj2};
template <obj T>
class A
{
public:
A(T);
private:
T t_;
};
template<obj T>
A<T>::A(T )
{}
template<>
A<obj1>::A(obj1 t):t_(t) {cout<<"case 1"<< endl;}
template<>
A<obj2>::A(obj2 t):t_(t) {cout<<"case 2"<< endl;}
int main()
{
obj test=obj1;
A<obj> a(test);
return 1;
}
Thank you for your help!
EDIT: It's clear that the code is wrong concerning type/value, but which mechanism can resemble such a switching of constructors?
You have to specialize on types, not on values. If you know the value at compile-time, you could use boost::mpl::int_ to do so. If you don't (like in your case), you'll have to live with plain old if.
I think the following is what you intended to do:
#include<iostream>
enum obj{obj1,obj2};
template<obj>
class A
{
public:
A();
private:
obj t_;
};
template<obj x>
A<x>::A() : t_(x){}
template<>
A<obj1>::A() : t_(obj1){ std::cout << "obj1\n"; }
template<>
A<obj2>::A() : t_(obj2){ std::cout << "obj1\n"; }
int main()
{
const obj x = obj1; // can only be used as the template argument below because it's a compile time constant
A<x> a;
return 0;
}
However this only works if you want to 'switch' on a compile time constant, and it sounds like you don't. You need to use a run time condition (if, switch, etc).
You are approaching the problem wrong. Templates are instantiated at compile-time so you can't choose a specialization based on a value that is present at runtime. Aside from other mistakes in your code this solution won't work.
A common solution to this kind of problem (creating different objects based on a parameter) is the abstract factory pattern. It means that you move the conditional constructing logic to a factory class and use virtual methods to avoid the need to write different code on the calling side (so essentially you make use of polymorphism).
You have to do something like this:
enum E
{
A,
B
};
template<E e>
struct A
{
};
template<>
struct A<E::A>
{
};
template<>
struct A<E::B>
{
};
int main()
{
A<E::B> ab;
}

Boost lambda with shared_ptr

If I have a polymorphic base class called Base as well as classes Derived1 and Derived2 which inherit from Base. I can then use boost::lambda to create a factory of sorts. Something like:
typedef boost::function<Base *()> Creator;
std::map<std::string,Creator> map1;
map1["Derived1"] = boost::lambda::new_ptr<Derived1>();
map1["Derived2"] = boost::lambda::new_ptr<Derived2>();
(This isn't real code, I'm just trying to illustrate the problem.)
This works, so I can then do a lookup in the map using a string and then invoke the lambda function to instantiate that class. All good.
The problem with this is that it's dealing in raw pointers, I'd prefer to be using smart pointers (std::shared_ptr).
So if I change from:
typedef boost::function<Base *>() Creator;
to:
typedef boost::function<std::shared_ptr<Base> >() Creator;
Then I'm getting stuck from here. I've tried using boost::lambda::bind in conjunction with boost::lambda::new_ptr but I'm not having much luck, can't get past compilation errors. (Huge reams of template-related error output.)
I've checked other similar messages within StackOverflow, Using boost::bind and boost::lambda::new_ptr to return a shared_ptr constructor is close but if I try to apply its solution I get the template errors mentioned above.
I'm happy to provide sample code and the actual errors if it helps, but hopefully the above info is sufficient. I'm using boost 1.47.0 on GCC 4.6 as well as 4.7 snapshot on Fedora 15.
class Base {
public:
virtual ~Base() = 0;
};
Base::~Base() {}
class Derived1 : public Base {};
class Derived2 : public Base {};
typedef boost::shared_ptr<Base> BasePtr;
typedef boost::function<BasePtr()> Creator;
template <typename T>
Creator MakeFactory()
{
namespace la = boost::lambda;
return la::bind(
la::constructor<BasePtr>(),
la::bind(la::new_ptr<T>()));
}
int _tmain(int argc, _TCHAR* argv[])
{
std::map<std::string,Creator> map1;
map1["Derived1"] = MakeFactory<Derived1>();
map1["Derived2"] = MakeFactory<Derived2>();
BasePtr p1 = map1["Derived1"]();
BasePtr p2 = map1["Derived2"]();
return 0;
}
however, why go to the trouble when you could write:
template <typename T>
BasePtr MakeFactoryImpl()
{
return BasePtr(new T());
}
template <typename T>
Creator MakeFactory()
{
return Creator(&MakeFactoryImpl<T>);
}
This is a common problem. The fact that two types are related (in your case by inheritance) does not imply that the instantiations of a template with those two types maintains the same relationship.
The solution is to return always shared_ptr<Base>, since it can hold both pointers to Base or any derived type, which will be semantically compatible with your current version (i.e. in both versions the caller gets a (smart)-pointer-to Base.
As an aside, I would avoid returning shared_ptr from a factory, as you are forcing your choice of smart pointer into all of your users. I would prefer to either return a raw pointer (the user can choose, but it is dangerous in some situations) or a unique_ptr or even auto_ptr, which are safe and still allow the user to choose a different mechanism (i.e. if your function returns an auto_ptr, the user can still use a shared_ptr by doing shared_ptr<Base> p( f().release() );, while the opposite is not possible (memory managed by a shared_ptr cannot be released to use in a different smart pointer.
This quick-and-dirty return type adapter is good not only for converting return types from Derived* to Base*, but between any convertible types. For simplicity, the function-object takes no arguments. With C++11 variadic templates it should be easy to add arbitrary argument handling. Feel free to improve on this in any way you wish.
template <typename ToType>
class return_type_adapter
{
template <typename toType>
class return_type_adapter_impl_base
{
public:
virtual toType call() = 0;
};
template <typename toType, typename Func>
class return_type_adapter_impl : public return_type_adapter_impl_base<toType>
{
public:
return_type_adapter_impl (Func func) : func(func) {}
toType call() { return toType(func()); }
private:
Func func;
};
boost::shared_ptr<return_type_adapter_impl_base<ToType> > impl_base;
public:
ToType operator() () { return impl_base->call(); }
template <typename Func>
return_type_adapter (Func func) :
impl_base(new return_type_adapter_impl<ToType, Func>(func)) {}
};
map1["Derived1"] = boost::lambda::bind(
boost::lambda::constructor<boost::shared_ptr<Base>>(),
boost::lambda::bind(
boost::lambda::new_ptr<Derived1>()));
map1["Derived2"] = boost::lambda::bind(
boost::lambda::constructor<boost::shared_ptr<Base>>(),
boost::lambda::bind(
boost::lambda::new_ptr<Derived2>()));
But honestly, this is the level of complexity where it doesn't really make sense to use boost lambda any more. A simpler solution:
template<typename DerivedType>
boost::shared_ptr<Base> makeDerived() {
return boost::shared_ptr<Base>(new DerivedType);
}
[...]
map1["Derived1"] = makeDerived<Derived1>;
map1["Derived2"] = makeDerived<Derived2>;