Static cast base to derived pointer and construct derived members - c++

A minimal example of what I want: I have two classes
template<typename T>
struct General;
template<typename T>
struct Specific;
with Specific inheriting from General, but General calling a Specific member function in its constructor:
template<typename T>
struct Specific: public General<T> {
int y;
void compute() {
y=x;
this->x++;
}
};
template<typename T>
struct General {
int x;
General(int x) : x(x) { static_cast<Specific<T>*>(this)->compute(); };
};
The idea is that there is one General class and multiple specific ones, and which one to use is decided either at run time or compile time.
The code above compiles and runs correctly, even though y is never actually constructed. I think I get away with it because it's a primitive type, but if I use a more complicated y instead:
template<typename T>
struct Specific: public General<T> {
std::vector<int> y;
void compute() {
y={0}; //anything here
this->x++;
}
};
then the code still compiles, but when executing the line with the comment I get a read access violation error because y hasn't been constructed.
There is a way out of it, and that's to have the variable y in General as opposed to Specific. This works, but different implementations need different variables, and it's not very elegant to include lots of protected variables in General that are only used by one implementation each (although from a performance standpoint, I guess compilers remove unused member variables as long as that can be detected in compile-time correct?). So is there a better way to do it?
Edit: One possible way suggested by Scheff:
General(int x) : x(x) {
Specific<T> B;
B = static_cast<Specific<T>&>(*this);
B.compute();
*this = static_cast<General<T>&>(B);
}

"Upgrading" a base class to a derived class is not going to happen. If I say
General<int> g(5)
I asked for a General<int> and I will get a General<int>. A Specific<int> is not a General<int>, and it would be wrong for me to get one. Indeed, since your Specific is larger than General, constructing a Specific where a General is expected corrupts the stack, even in the first example with two ints.
Deciding which subclass of General to instantiate belongs outside of its constructor, period. The most obvious way to get there is to untangle the initialization into normal constructors:
template<typename T>
struct General {
int x;
General(int x) : x(x) { }
virtual ~General() { }
};
template<typename T>
struct Specific : General<T> {
int y;
Specific(int x) : General<T>(x), y(this->x++) { }
};
and to decide which one to actually instantiate in a free function:
template<typename T>
std::unique_ptr<General<T>> DecideGeneral(int x) {
if(foo) return std::make_unique<Specific<T>>(x);
// other cases...
else return std::make_unique<General<T>>(x);
}
int main() {
// interesting tidbit:
// a const std::unique_ptr<T> is basically just a T, as the lifetime of the
// pointed-to object is exactly the same as the pointer's (it can't move out)
// all accesses are still indirect though
const auto g = DecideGeneral<int>(5);
}

Related

Template declaration inside if statement [duplicate]

Suppose I have a class template which have a member pData, which is an AxB array of arbitary type T.
template <class T> class X{
public:
int A;
int B;
T** pData;
X(int a,int b);
~X();
void print(); //function which prints pData to screen
};
template<class T>X<T>::X(int a, int b){ //constructor
A = a;
B = b;
pData = new T*[A];
for(int i=0;i<A;i++)
pData[i]= new T[B];
//Fill pData with something of type T
}
int main(){
//...
std::cout<<"Give the primitive type of the array"<<std::endl;
std::cin>>type;
if(type=="int"){
X<int> XArray(a,b);
} else if(type=="char"){
X<char> Xarray(a,b);
} else {
std::cout<<"Not a valid primitive type!";
} // can be many more if statements.
Xarray.print() //this doesn't work, as Xarray is out of scope.
}
As the instance Xarray is constructed inside of an if statement, I cannot use it anywhere else. I tried to make a pointer before the if statements but as the type of the pointer is unknown at that point, I did not succeed.
What would be a proper way of dealing with this kind of a problem?
The problem here is that X<int> and x<char> are completely unrelated types.
The fact that they are both a result of the same templated class won't help here.
I can see several solutions, but those depends on what you really need.
You could, for instance make the X<> instances derive from a common non-templated base class that has the print() method (eventually as a pure virtual). But before you do that, be sure that it makes sense on a functional level: one should use inheritance because it makes sense, not solely because of technical constraints. And if you do that, you probably will want to have a virtual destructor as well.
You could also bind and store a std::function<void ()> to the method you want to call, but ensure that the objects are still "alive" (they aren't in your current code: both the X<int> and X<char> are destroyed when they go out of scope, way before you actually call print()).
A final solution would be to make some variant type that is compatible with both X<int> and X<char> (boost::variant<> can help here). You could then write a visitor that implements the print() functionality for each type.
Picking the last solution, it would become something like:
typedef boost::variant<X<int>, X<char>> genericX;
class print_visitor : public boost::static_visitor<void>
{
public:
template <typename SomeType>
void operator()(const SomeType& x) const
{
// Your print implementation
// x is your underlying instance, either X<char> or X<int>.
// You may also make several non-templated overloads of
// this operator if you want to provide different implementations.
}
};
int main()
{
boost::optional<genericX> my_x;
if (type=="int") {
my_x = X<int>(a,b);
} else if(type=="char") {
my_x = X<char>(a,b);
}
// This calls the appropriate print.
if (my_x) {
boost::apply_visitor(print_visitor(), *my_x)
}
}
We actually lack the knowledge to give a definitive answer: if your classes are "entities", then you probably should go for inheritance. If they are more like "value classes", then the variant way might be more suited.
C++ is a statically typed language, meaning that you must know the type of objects at compile time. In this case you are basing the type of the object constructed on user input, so it's not possible to know the type at runtime.
The most common way to address this issue is to use dynamic polymorphism in which functions are invoked via a common interface using late binding. We accomplish this in C++ using virtual functions. For example:
struct IPrintable {
virtual void print() = 0;
};
template<class T>
class X : public IPrintable {
// Same code as you showed above.
};
int main() {
std::cout<<"Give the primitive type of the array"<<std::endl;
std::cin>>type;
std::unique_ptr<IPrintable> XArray;
if(type=="int"){
XArray.reset(new X<int>(a,b));
} else if(type=="char"){
XArray.reset(new X<char>(a,b));
} else {
std::cout<<"Not a valid primitive type!";
} // can be many more if statements.
Xarray->print() // this works now!
}
This solves the out of scope issue and allows you to print using the dynamic type of the XArray variable. Virtual functions are the secret sauce that make this possible.
Rather than trying to fit the templates into main I would go the opposite way than the rest of the suggestions... move the code out of main and into it's own (possibly templated) function that needs to deal with a single type:
template <typename T>
void generateAndPrint(int a, int b) {
X<T> x(a,b);
x.print();
}
int main() { ...
if (type=="int") generateAndPrint<int>(a,b);
else if (type=="char") generateAndPrint<char>(a,b);
else ...
}
If you want to work with different arrays, whatever their type, templates alone cannot help you. Currently, there is exactly no relationship between X<int> and X<char>.
If you want to treat them as two subtypes of a common type, you will have to use inheritance (and dynamically allocated variables). For instance, all X<T> may inherit the same base class, say Printable, and you can store the data in a unique_ptr<Printable>:
unique_ptr<Printable> r;
if(type=="int"){
r.reset(new X<int>(a,b));
} else if(type=="char"){
r.reset(new X<char>(a,b);
}
r->print();
But this is probably not the best design.
A probably better solution would be, instead of trying to work outside of the if, to move all the work inside of the if. In your simple example, this could be done by duplicating the call to print, but this is not pretty nice either. But, going toward this idea, we can create a template function that does the job:
template<class T>
void workWithType(int a, int b)
{
X<T> Xarray(a, b);
Xarray.print();
}
//...
if(type=="int"){
workWithType<int>(a,b);
} else if(type=="char"){
workWithType<char>(a,b);
}

Value to type runtime mapping

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)?

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.

How to get instance of class template out of the if statement? (C++)

Suppose I have a class template which have a member pData, which is an AxB array of arbitary type T.
template <class T> class X{
public:
int A;
int B;
T** pData;
X(int a,int b);
~X();
void print(); //function which prints pData to screen
};
template<class T>X<T>::X(int a, int b){ //constructor
A = a;
B = b;
pData = new T*[A];
for(int i=0;i<A;i++)
pData[i]= new T[B];
//Fill pData with something of type T
}
int main(){
//...
std::cout<<"Give the primitive type of the array"<<std::endl;
std::cin>>type;
if(type=="int"){
X<int> XArray(a,b);
} else if(type=="char"){
X<char> Xarray(a,b);
} else {
std::cout<<"Not a valid primitive type!";
} // can be many more if statements.
Xarray.print() //this doesn't work, as Xarray is out of scope.
}
As the instance Xarray is constructed inside of an if statement, I cannot use it anywhere else. I tried to make a pointer before the if statements but as the type of the pointer is unknown at that point, I did not succeed.
What would be a proper way of dealing with this kind of a problem?
The problem here is that X<int> and x<char> are completely unrelated types.
The fact that they are both a result of the same templated class won't help here.
I can see several solutions, but those depends on what you really need.
You could, for instance make the X<> instances derive from a common non-templated base class that has the print() method (eventually as a pure virtual). But before you do that, be sure that it makes sense on a functional level: one should use inheritance because it makes sense, not solely because of technical constraints. And if you do that, you probably will want to have a virtual destructor as well.
You could also bind and store a std::function<void ()> to the method you want to call, but ensure that the objects are still "alive" (they aren't in your current code: both the X<int> and X<char> are destroyed when they go out of scope, way before you actually call print()).
A final solution would be to make some variant type that is compatible with both X<int> and X<char> (boost::variant<> can help here). You could then write a visitor that implements the print() functionality for each type.
Picking the last solution, it would become something like:
typedef boost::variant<X<int>, X<char>> genericX;
class print_visitor : public boost::static_visitor<void>
{
public:
template <typename SomeType>
void operator()(const SomeType& x) const
{
// Your print implementation
// x is your underlying instance, either X<char> or X<int>.
// You may also make several non-templated overloads of
// this operator if you want to provide different implementations.
}
};
int main()
{
boost::optional<genericX> my_x;
if (type=="int") {
my_x = X<int>(a,b);
} else if(type=="char") {
my_x = X<char>(a,b);
}
// This calls the appropriate print.
if (my_x) {
boost::apply_visitor(print_visitor(), *my_x)
}
}
We actually lack the knowledge to give a definitive answer: if your classes are "entities", then you probably should go for inheritance. If they are more like "value classes", then the variant way might be more suited.
C++ is a statically typed language, meaning that you must know the type of objects at compile time. In this case you are basing the type of the object constructed on user input, so it's not possible to know the type at runtime.
The most common way to address this issue is to use dynamic polymorphism in which functions are invoked via a common interface using late binding. We accomplish this in C++ using virtual functions. For example:
struct IPrintable {
virtual void print() = 0;
};
template<class T>
class X : public IPrintable {
// Same code as you showed above.
};
int main() {
std::cout<<"Give the primitive type of the array"<<std::endl;
std::cin>>type;
std::unique_ptr<IPrintable> XArray;
if(type=="int"){
XArray.reset(new X<int>(a,b));
} else if(type=="char"){
XArray.reset(new X<char>(a,b));
} else {
std::cout<<"Not a valid primitive type!";
} // can be many more if statements.
Xarray->print() // this works now!
}
This solves the out of scope issue and allows you to print using the dynamic type of the XArray variable. Virtual functions are the secret sauce that make this possible.
Rather than trying to fit the templates into main I would go the opposite way than the rest of the suggestions... move the code out of main and into it's own (possibly templated) function that needs to deal with a single type:
template <typename T>
void generateAndPrint(int a, int b) {
X<T> x(a,b);
x.print();
}
int main() { ...
if (type=="int") generateAndPrint<int>(a,b);
else if (type=="char") generateAndPrint<char>(a,b);
else ...
}
If you want to work with different arrays, whatever their type, templates alone cannot help you. Currently, there is exactly no relationship between X<int> and X<char>.
If you want to treat them as two subtypes of a common type, you will have to use inheritance (and dynamically allocated variables). For instance, all X<T> may inherit the same base class, say Printable, and you can store the data in a unique_ptr<Printable>:
unique_ptr<Printable> r;
if(type=="int"){
r.reset(new X<int>(a,b));
} else if(type=="char"){
r.reset(new X<char>(a,b);
}
r->print();
But this is probably not the best design.
A probably better solution would be, instead of trying to work outside of the if, to move all the work inside of the if. In your simple example, this could be done by duplicating the call to print, but this is not pretty nice either. But, going toward this idea, we can create a template function that does the job:
template<class T>
void workWithType(int a, int b)
{
X<T> Xarray(a, b);
Xarray.print();
}
//...
if(type=="int"){
workWithType<int>(a,b);
} else if(type=="char"){
workWithType<char>(a,b);
}

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;
}