Here is what I am trying to do in C++. From an external library that I use I have 3 classes, MyClass1
, MyClass2
and MyClass3
that are identical in their public functions. I would like to decide, at the beginning of runtime, which one will be used by in the rest of my code depending on the hardware configuraion of the user.
To better illustrate what I mean, let me give an example that I know does not work. If it were possible to conditionally define a typedef
at runtime, what I am trying to achieve would look as follows:
const int x = GetX(); //where GetX() is any function that calculates the value of x
typedef std::conditional<x > 0, MyClass1,
std::conditional< x < 0, MyClass2,
MyClass3>::type>::type TheClass;
So that in the rest of the code I would only refer to TheClass
, in such a way that it does not matter whether it is aliasing MyClass1
, MyClass2
or MyClass3
.
However, of course the code above does not work because when x
has its value calculated from a function executed at the beginning of runtime, then std::conditional
complains that x
is not a constant. Which makes sense since typedef
cannot be defined at runtime.
So, my question: is there a way to achieve what I am trying to do (not with typedef
since I know it cannot be defined at runtime)? Remember that MyClass1
, MyClass2
and MyClass3
are externally given by a library, and in such a way that I cannot easily alter them.
To do this at compile time, the GetX function must be constexpr
.
Using the comparison operators also conflicts with the template syntax. You will need to provide consexpr functions for less than and greater than:
constexpr int GetX(){ return 0;}
constexpr bool IsGreater(int x, int y) { return x > y;}
constexpr bool IsLess(int x, int y) { return x < y;}
typedef std::conditional<IsGreater(GetX(),0), MyClass1,
std::conditional<IsLess(GetX(),0), MyClass2,
MyClass3>::type>::type TheClass;
If you can't make GetX()
constexpr (because the value is decided at runtime),
then you are looking for a Sum Type. They are quite common in functional programming languages and C++ now has library support in the form of std::variant.
Your example code could be turned into the following:
int main(){
//a type that can be 1 of 3 other types
std::variant<MyClass1,MyClass2,MyClass3> TheClass;
//decide what type it should be at runtime.
const int x = GetX();
if (x > 0) { TheClass = MyClass1(); }
else if (x < 0) { TheClass = MyClass2(); }
else { TheClass = MyClass3(); }
}
Here, you are deciding the type at runtime.
You can go on to use pattern matching for evaluating what type is held.