Polymorphic value types and interfaces - c++

I have a polymorphic value type implemented like so:
class ShapeValue {
public:
template<class T>
ShapeValue(const T& value) {
obj = make_unique<holder<T>>(value);
}
// ... appropriate copy constructors and such
void draw() { obj->draw(); }
private:
struct base {
virtual ~base() {}
virtual void draw() = 0;
};
template<class T>
struct holder<T> : public base {
T value;
void draw() override { value.draw(); }
}
unique_ptr<base> obj;
};
If you aren't familiar with this sort of thing, here's a good talk.
Ok, that's great. But now what if I want to cast my underlying object to some other interface?
Here's my motivation. Previously, I had defined things the typical way, like so:
class Shape {
virtual void draw() = 0;
};
and then I would define other interfaces, like:
class HasColor {
virtual Color color() = 0;
virtual void setColor(Color) = 0;
};
so I could define a shape as follows:
class MyShape : public Shape, public HasColor {
void draw() override;
Color color() override;
void setColor(Color) override;
};
So if I have a bunch of selected shapes and I want to set their color, I could iterate over all shapes and dynamic_cast<HasColor*>. This proves to be quite convenient (my actual app isn't a drawing app, by the way, but has analogous data).
Can I do this for my polymorphic value type, in a way that my ShapeValue interface doesn't need to know about every Has interface? I could do the following, which isn't actually so bad, but not ideal:
HasColor* ShapeValue::toHasColor() { return obj->toHasColor(); }

A solution (tested) is to have a base class for the interfaces:
class AnyInterface {
virtual ~AnyInterface() {} // make it polymorphic
};
struct HasColor : public AnyInterface {
// ... same stuff
};
So then we have the following:
vector<AnyInterface*> ShapeValue::getInterfaces() { return _obj->getInterfaces(); }
Could then define a helper to grab the interface we want:
template<class I>
I* hasInterface(Shape& shape) {
for(auto interface : shape.getInterfaces()) {
if(auto p = dynamic_cast<I*>(interface)) {
return p;
}
}
return nullptr;
}
This way ShapeValue does not need to know about all the interface types.

The accepted answer seems likely a viable solution though I haven't tested it and it does seem to fallback to reference semantics. A motivating factor however for polymorphic value types is instead value semantics.
What follows is a description of a more value semantic oriented alternative solution where ShapeValue doesn't need to know about all the interface types, albeit external user-definable free functions sort of do instead.
As I've been using polymorphic value types, I've preferred to recognize two categories of functionality of those values:
Functionality required of all eligible value types. I.e. the functionality enforced by the virtual methods of this base polymorphic concept class.
Optional/extended functionality which some, none, or all eligible value types may provide.
It seems like your question is more about how to deal this second category (than the first).
For this second category, I've borrowed on the implementation of std::any's type member function and std::any's non-member any_cast template functions. With these two functional concepts, the set of value types, which implement some optional extended functionality, is open (like namespaces are open to additions contrary to classes) and your ShapeValue's interface doesn't need to know about every optional extension. As an added bonus, no extended functionality needs to be implemented using type polymorphism - i.e. the value types eligible for use with ShapeValue construction, don't have to have any kind of inheritance relationship or virtual functions.
Here's an example of pseudo code extending the question's code for this:
class ShapeValue {
public:
template<class T>
ShapeValue(const T& value) {
obj = make_unique<holder<T>>(value);
}
// ... appropriate copy constructors and such
ShapeValue& operator=(const ShapeValue& newValue) {
obj = newValue.obj? newValue.obj->clone(): nullptr;
return *this;
}
const std::type_info& type() const noexcept {
return obj? obj->type_(): typeid(void);
}
void draw() { obj->draw(); }
template <typename T>
friend auto type_cast(const ShapeValue* value) noexcept {
if (!value || value->type() != typeid(std::remove_pointer_t<T>))
return static_cast<T>(nullptr);
return static_cast<T>(value->obj->data_());
}
private:
struct base {
virtual ~base() = default;
virtual void draw() = 0;
virtual std::unique_ptr<base> clone_() const = 0;
virtual const std::type_info& type_() const noexcept = 0;
virtual const void* data_() const noexcept = 0;
};
template<class T>
struct holder final: base {
T value;
void draw() override { value.draw(); }
std::unique_ptr<base> clone_() const override {
return std::make_unique<holder>(value);
}
const std::type_info& type_() const noexcept override { return typeid(T); }
const void* data_() const noexcept override { return &value; }
};
unique_ptr<base> obj;
};
template <typename T>
inline auto type_cast(const ShapeValue& value)
{
auto tmp = type_cast<std::add_pointer_t<std::add_const_t<T>>>(&value);
if (tmp == nullptr)
throw std::bad_cast();
return *tmp;
}
struct Square {
int side_;
Color color_;
void draw();
Color color() { return color_; }
void setColor(Color value) { color_ = value; }
};
Color color(const ShapeValue& value)
{
if (value.type() == typeid(Square)) {
return type_cast<Square>(value).color();
}
throw std::invalid_argument("color not supported for value's type");
}
void setColor(ShapeValue& value, Color newColor)
{
if (value.type() == typeid(Square)) {
auto square = type_cast<Square>(value);
square.setColor(newColor);
value = square;
return;
}
throw std::invalid_argument("setColor not supported for value's type");
}
For a more elaborate, compilable, tested, and typeid/std::type_info-free example, one can take a look at the source code for the Joint polymorphic value type I just finished that provides an interface to value types for constraining the movements of one or more bodies. I wouldn't say it's perfect, but it's also more value semantics oriented like the example above that I've included in this answer.

Related

CRTP Parameter for Virtual Method of Class Hierarchy

I am trying to pass a CRTP type parameter to a virtual method. Consequently, the virtual method would need to be a template. However, this is not allowed by C++ (yet?), because it would mean that the size of the vtable -- the common way how compilers implement dynamic dispatch -- is unknown until all sources have been compiled and are being linked. (I found this reasoning during my search on SO.)
In my particular setting, however, there is a finite and known amount of CRTP specializations. Hence, it is possible to define a virtual method overload per specialization and override these in the subclasses. I have prepared a small MWE to demonstrate my situation. Consider the following CRTP hierarchy:
template<typename Actual>
struct CRTPBase
{
using actual_type = Actual;
void foo() { static_cast<actual_type*>(this)->foo(); }
int bar(int i) const { return static_cast<const actual_type*>(this)->bar(i); }
};
struct A : CRTPBase<A>
{
void foo() { /* do something A would do */ }
int bar(int i) const { return i + 1; }
};
struct B : CRTPBase<B>
{
void foo() { /* do something B would do */ }
int bar(int i) const { return i - 1; }
};
Next, I want to define a virtual class hierarchy with a virtual method to handle all specializations of CRTPBase<T>. Because I know the particular specializations, I can do as follows:
struct VirtualBase
{
virtual ~VirtualBase() { }
virtual void accept_crtp(const CRTPBase<A> &o) = 0;
virtual void accept_crtp(const CRTPBase<B> &o) = 0;
};
struct VirtualDerived : VirtualBase
{
void accept_crtp(const CRTPBase<A> &o) override { /* much logic to handle A */ }
void accept_crtp(const CRTPBase<B> &o) override { /* similar logic to handle B */ }
};
Observe that there is one virtual method per specialization of CRTPBase<T>, both in the purely virtual base and in all its derived classes. This overhead easily blows out of proportion with increasing number of specializations of CRTPBase<T> and more derived classes of VirtualBase.
What I would like to do, is roughly the following:
struct VirtualBase
{
virtual ~VirtualBase() { }
template<typename T> virtual void accept_crtp(const CRTPBase<T> &o) = 0;
}
struct VirtualDerived : VirtualBase
{
template<typename T> void accept_crtp(const CRTPBase<T> &o) override {
/* one logic to handle any CRTPBase<T> */
}
};
For the reason mentioned in the beginning, this is not possible. User Mark Essel has faced the same issue in another SO post (in an answer, not a question, though).
The user proposes to declare and define the virtual methods for each specialization, but in the derived classes implement the actual logic in an additional template, non-virtual method and then forward calls from the virtual methods to that template method:
struct VirtualBase
{
virtual ~VirtualBase() { }
virtual void accept_crtp(const CRTPBase<A> &o) = 0;
virtual void accept_crtp(const CRTPBase<B> &o) = 0;
};
struct VirtualDerived : VirtualBase
{
void accept_crtp(const CRTPBase<A> &o) override { accept_any_crtp(o); }
void accept_crtp(const CRTPBase<B> &o) override { accept_any_crtp(o); }
private:
template<typename T>
void accept_any_crtp(const CRTPBase<T> &o) {
/* one logic to handle any CRTPBase<T> */
}
};
While this approach avoids code duplication of the logic to handle the CRTPBase<T> specializations, it still requires explicitly writing one method per specialization in the virtual base and all derived classes.
My question is: How can the implementation overhead be reduced?
I have considered using an X macro of the form
#define CRTP_SPECIALIZATIONS_LIST(X) X(A) X(B) // lists all specializations, here A and B
to generate the methods in the virtual base and derived classes. The problem with that is, if the CRTP hierarchy is defined in CRTP.hpp and the virtual base and derived classes are declared/defined in other source files, then the macro is "being leaked" by the header to all translation units that include it. Is there a more elegant way to solve this? Is there maybe a template way of achieving the same goal, perhaps with a variadic template type?
Your help is appreciated. Kind regards,
Immanuel
As all types are known, you might use std::variant to have a free visitor implementation:
using MyVariant =
std::variant<std::reference_wrapper<const CRTPBase<A>>,
std::reference_wrapper<const CRTPBase<B>>,
// ...
>
struct VirtualBase
{
virtual ~VirtualBase() { }
virtual void accept_crtp(MyVariant) = 0;
};
struct VirtualDerived : VirtualBase
{
void accept_crtp(MyVariant var) override
{
std::visit([/*this*/](const auto& crtp){ /*...*/ }, var);
}
};
If you write a CRTP base with the different accept_crtp() overloads that all delegate to a derived class' method, that derived class' method can be a template. That CRTP base can also be used to implement a virtual base:
// declare virtual interface
struct VirtualBase
{
virtual ~VirtualBase() { }
virtual void accept_crtp(const CRTPBase<A> &o) = 0;
virtual void accept_crtp(const CRTPBase<B> &o) = 0;
};
// implement virtual interface by delegating to derived class generic method
template<typename DerivedType>
struct CRTPDerived : VirtualBase
{
using derived_type = DerivedType;
virtual void accept_crtp(const CRTPBase<A> &o)
{ static_cast<derived_type*>(this)->accept_any_crtp(o); }
virtual void accept_crtp(const CRTPBase<B> &o)
{ static_cast<derived_type*>(this)->accept_any_crtp(o); }
};
// implement generic method
struct VirtualDerived : CRTPDerived<VirtualDerived>
{
private:
template<typename T>
void accept_any_crtp(const CRTPBase<T> &o) {
/* one logic to handle any CRTPBase<T> */
}
};
I have found a convenient solution to my problem. It scales well, meaning that the amount of code grows linearly with the number of virtual methods (rather than having number of virtual methods times number of CRTP classes). Further, my solution resolves the actual type of CRTPBase<T> at compile time; no dynamic dispatch except for the virtual method call. Thanks to Ulrich Eckhardt for pointing me in the right direction with his idea of using CRTP in the class hierarchy of VirtualBase.
I will describe how to solve this for a single method. This process can then be repeated for each method. The idea is to generate a purely virtual method in the VirtualBase for each concrete type of CRTPBase<T> and to generate implementations of these methods in all derived classes. The problem with generating methods at compile time is that templates do not allow us to generate method names. The trick here is to exploit overloading semantics and use a tag type to perform tag dispatching.
Let me explain along the example. Given the CRTP hierarchy (note that i slightly changed it for demonstrational purpose)
template<typename Actual>
struct CRTPBase
{
using actual_type = Actual;
actual_type & actual() { return *static_cast<actual_type*>(this); }
const actual_type & actual() const {
return *static_cast<const actual_type*>(this);
}
void foo() const { actual().foo(); }
int bar(int i) const { return actual().bar(i); }
void baz(float x, float y) { actual().baz(x, y); }
};
struct A : CRTPBase<A>
{
void foo() const { }
int bar(int i) const { return i + 'A'; }
void baz(float x, float y) { }
};
struct B : CRTPBase<B>
{
void foo() const { }
int bar(int i) const { return i + 'B'; }
void baz(float x, float y) { }
};
we want to declare a virtual method bark() in the class hierarchy VirtualBase, that accepts any subclass of CRTPBase<T> as parameter. We create a helper tag type bark_t to enable overload resolution.
struct VirtualBase
{
private:
virtual void operator()(bark_t, const A&) const = 0;
virtual void operator()(bark_t, const B&) const = 0;
public:
template<typename T>
void bark(const T &o) const { operator()(bark_t{}, o); }
};
The template method is generic and calls to the proper operator() thanks to overload resolution. The tag type is used here to select the correct implementation. (We want to support multiple methods, not just bark().)
Next we define an implementation of operator() in the derived classes using CRTP:
template<typename Actual>
struct VirtualCRTP : VirtualBase
{
using actual_type = Actual;
actual_type & actual() { return *static_cast<actual_type*>(this); }
const actual_type & actual() const {
return *static_cast<const actual_type*>(this);
}
void operator()(bark_t{}, const A &o) const override { actual()(bark_t{}, o); }
void operator()(bark_t{}, const B &o) const override { actual()(bark_t{}, o); }
};
Note that the implementation calls to some method operator() of static type Actual. We need to implement this next in the implementations of VirtualBase:
struct VirtualDerivedX : VirtualCRTP<VirtualDerivedX>
{
template<typename T>
void operator()(bark_t, const T &o) { /* generic implementation goes here */ }
};
struct VirtualDerivedY : VirtualCRTP<VirtualDerivedY>
{
template<typename T>
void operator()(bark_t, const T &o) { /* generic implementation goes here */ }
};
At this point you might wonder "What did we gain here?". So far, we need to write one method operator() per actual type of CRTPBase<T>. Only in VirtualBase and VirtualCRTP, but still more than we want to write. The neat thing is, we can now generate methods operator(), both the purely virtual declarations in VirtualBase and the implementation in VirtualCRTP. To do so, I have defined a generic helper class. I put the full code with this helper class and the example on Godbolt.
We can use this helper class to declare new virtual methods that take as first parameter an instance of a list of types, as well as additional parameters. It also takes care of const-ness of the parameters and the methods.
struct bark_t : const_virtual_crtp_helper<bark_t>::
crtp_args<const A&, const B&>::
args<> { };
struct quack_t : virtual_crtp_helper<quack_t>::
crtp_args<const A&, const B&>::
args<int, float> { };
struct roar_t : const_virtual_crtp_helper<roar_t>::
crtp_args<A&, B&>::
args<const std::vector<int>&> { };
/*----- Virtual Class Hierarchy taking CRTP parameter ------------------------*/
struct VirtualBase : bark_t::base_type
, quack_t::base_type
, roar_t::base_type
{
virtual ~VirtualBase() { }
/* Declare generic `bark()`. */
using bark_t::base_type::operator();
template<typename T>
void bark(const T &o) const { operator()(bark_t{}, o); }
/* Declare generic `quack()`. */
using quack_t::base_type::operator();
template<typename T>
void quack(const T &o, int i, float f) { operator()(quack_t{}, o, i, f); }
/* Declare generic `roar()`. */
using roar_t::base_type::operator();
template<typename T>
void roar(T &o, const std::vector<int> &v) const { operator()(roar_t{}, o, v); }
};
template<typename Actual>
struct VirtualCRTP : VirtualBase
, bark_t::derived_type<Actual>
, quack_t::derived_type<Actual>
, roar_t::derived_type<Actual>
{ };
struct VirtualDerivedX : VirtualCRTP<VirtualDerivedX>
{
private:
/* Implement generic `bark()`. */
friend const_virtual_crtp_helper<bark_t>;
template<typename T>
void operator()(bark_t, const T&) const { /* generic bark() goes here */ }
/* Implement generic `quack()`. */
friend virtual_crtp_helper<quack_t>;
template<typename T>
void operator()(quack_t, const T&, int, float) { /* generic quack() goes here */ }
/* Implement generic `roar()`. */
friend const_virtual_crtp_helper<roar_t>;
template<typename T>
void operator()(roar_t, T&, const std::vector<int>&) const { /* generic roar() goes here */ }
};
struct VirtualDerivedY : VirtualCRTP<VirtualDerivedY>
{
private:
/* Implement generic `bark()`. */
friend const_virtual_crtp_helper<bark_t>;
template<typename T>
void operator()(bark_t, const T&) const { /* generic bark() goes here */ }
/* Implement generic `quack()`. */
friend virtual_crtp_helper<quack_t>;
template<typename T>
void operator()(quack_t, const T&, int, float) { /* generic quack() goes here */ }
/* Implement generic `roar()`. */
friend const_virtual_crtp_helper<roar_t>;
template<typename T>
void operator()(roar_t, T&, const std::vector<int>&) const { /* generic roar() goes here */ }
};
In the example I declare three helper types for the three methods I want to implement. The base_type introduces the purely virtual methods to VirtualBase and the derived_type<Actual> imports the implementations of these methods. To do so, I use virtual inheritance to resolve the occuring dreaded diamond ;)
One downside is that one has to declare virtual_crtp_helper types as friend in the derived classes. Maybe someone knows how to avoid that?
To sum up: To add a method to the class hierarchy, one has to
Declare a helper type for the method using virtual_crtp_helper<T> or const_virtual_crtp_helper<T>.
Have VirtualBase inherit from this type's base_type and define the method as generic template.
Have VirtualCRTP<Actual> inherit from the helper type's derived_type<Actual>.
For each derived class, implement the actual logic in templated and tagged operator().
I am happy to hear your thoughts and am looking forward to improvements.
Immanuel

Polymorphism with a vector of a template class [duplicate]

class A
{
friend void foo();
virtual void print_Var() const{};
};// does not contain variable Var;
template<class T>
class B : public A
{
T Var;
public:
B(T x):Var(x){}
void print_Var() const override
{
std::cout<<Var<<std::endl;
}
};
void foo()
{
std::array<std::unique_ptr<A>, 3> Arr = {
std::make_unique<B<int>>(100),
std::make_unique<B<int>>(20),
std::make_unique<B<std::string>>("Hello Stackoverflow")
};
std::shuffle(Arr.begin(), Arr.end(), std::mt19937(std::random_device()())); // 3rd parameter generated by Clang-Tidy
for (auto &i: Arr)
{
i->print_Var(); // OK
// auto z = i->Var // no member named Var in A
// obviously base class does not contain such variable
// if (i->Var==20) {/* do something*/}
// if (i->Var=="Hello Stackoverflow") {/* do something*/}
}
}
Explanation:
I want to iterate over array of pointers to A, which is filled with pointers to classes derived from A, and depending on what type is variable Var, do some if( ) statement.
Problem is that i cannot access Var, cause its not member of base class. However, it's possible to cout those values by, for example, overloaded function returning void. Could i write function in A class that returns templated type? like:
class A
{
<class T> GetVar()
}
Besides, I feel like I'm dealing with this problem in totally improper way. Can i mix templates and inheritance like that? If not, how should it be designed?
You have a few choices. I'll explain my preferred solution first.
1. Use dynamic dispatch
If you have an array of a base class type, why do you even want to do stuff with Var? That variable is specific to the child class. If you have a A somewhere, you shouldn't even care what B has or hasn't at that place.
Operations on the typed variable should be encapsulated in virtual function in the base class. If you want to do condition and stuff, maybe you could encapsulate that condition into a virtual function that returns a boolean.
2a. Drop the base class and use variant
Sometimes, you know in advance the amount of types that will go into that list. Using a variant and drop the base class is a good solution that may apply to your case.
Let's say you only have int, double and std::string:
using poly = std::variant<B<int>, B<double>, B<std::string>>;
std::array<poly, 3> arr;
arr[0] = B<int>{};
arr[1] = B<double>{};
arr[2] = B<std::string>{};
// arr[2] = B<widget>{}; // error, not in the variant type
std::visit(
[](auto& b) {
using T = std::decay_t<decltype(b)>;
if constexpr (std::is_same_v<B<int>, T>) {
b.Var = 2; // yay!
}
},
arr[0]
);
2b. Drop the base class and use generic functions
Drop the base class entirely, and template your functions that do operation on them. You can move all your function into an interface or many std::function. Operate on that instead of the function directly.
Here's an example of what I meant:
template<typename T>
void useA(T const& a) {
a.Var = 34; // Yay, direct access!
}
struct B {
std::function<void()> useA;
};
void createBWithInt() {
A<int> a;
B b;
b.useA = [a]{
useA(a);
};
};
This is fine for cases where you only have few operations. But it can quickly lead to code bloat if you have a lot of operations or if you have many types of std::function.
3. Use a visitor
You could create a visitor that dispatch to the right type.
This solution would be much close to what you except, but is quite combersome and can break easily when adding cases.
Something like this:
struct B_Details {
protected:
struct Visitor {
virtual accept(int) = 0;
virtual void accept(double) = 0;
virtual void accept(std::string) = 0;
virtual void accept(some_type) = 0;
};
template<typename T>
struct VisitorImpl : T, Visitor {
void accept(int value) override {
T::operator()(value);
}
void accept(double) override {
T::operator()(value);
}
void accept(std::string) override {
T::operator()(value);
}
void accept(some_type) override {
T::operator()(value);
}
};
};
template<typename T>
struct B : private B_Details {
template<typename F>
void visit(F f) {
dispatch_visitor(VisitorImpl<F>{f});
}
private:
virtual void dispatch_visitor(Visitor const&) = 0;
};
// later
B* b = ...;
b->visit([](auto const& Var) {
// Var is the right type here
});
Then of course, you have to implement the dispatch_visitor for each child class.
4. Use std::any
This is litteraly returning the variable with type erasure. You cannot do any operation on it without casting it back:
class A {
std::any GetVar()
};
I personnaly don't like this solution because it can break easily and is not generic at all. I would not even use polymorphism in that case.
I think it will be the easiest way. Just move the comparison method to the interface and override it in derived classes. Add the following lines to yor example:
class A
{
/*..................................................*/
virtual bool comp(const int) const { return false; }
virtual bool comp(const std::string) const { return false; }
virtual bool comp(const double) const { return false; }
};
template<class T>
class B : public A
{
/*..................................................*/
virtual bool comp(const T othr) const override { return othr == Var; }
};
void foo()
{
/*..................................................*/
if (i->comp(20))
{
/* do something*/
}
if (i->comp("Hello Stackoverflow"))
{
/* do something*/
}
/*..................................................*/
}

How to use factories to generate an object of a template class with a specific type? [duplicate]

class A
{
friend void foo();
virtual void print_Var() const{};
};// does not contain variable Var;
template<class T>
class B : public A
{
T Var;
public:
B(T x):Var(x){}
void print_Var() const override
{
std::cout<<Var<<std::endl;
}
};
void foo()
{
std::array<std::unique_ptr<A>, 3> Arr = {
std::make_unique<B<int>>(100),
std::make_unique<B<int>>(20),
std::make_unique<B<std::string>>("Hello Stackoverflow")
};
std::shuffle(Arr.begin(), Arr.end(), std::mt19937(std::random_device()())); // 3rd parameter generated by Clang-Tidy
for (auto &i: Arr)
{
i->print_Var(); // OK
// auto z = i->Var // no member named Var in A
// obviously base class does not contain such variable
// if (i->Var==20) {/* do something*/}
// if (i->Var=="Hello Stackoverflow") {/* do something*/}
}
}
Explanation:
I want to iterate over array of pointers to A, which is filled with pointers to classes derived from A, and depending on what type is variable Var, do some if( ) statement.
Problem is that i cannot access Var, cause its not member of base class. However, it's possible to cout those values by, for example, overloaded function returning void. Could i write function in A class that returns templated type? like:
class A
{
<class T> GetVar()
}
Besides, I feel like I'm dealing with this problem in totally improper way. Can i mix templates and inheritance like that? If not, how should it be designed?
You have a few choices. I'll explain my preferred solution first.
1. Use dynamic dispatch
If you have an array of a base class type, why do you even want to do stuff with Var? That variable is specific to the child class. If you have a A somewhere, you shouldn't even care what B has or hasn't at that place.
Operations on the typed variable should be encapsulated in virtual function in the base class. If you want to do condition and stuff, maybe you could encapsulate that condition into a virtual function that returns a boolean.
2a. Drop the base class and use variant
Sometimes, you know in advance the amount of types that will go into that list. Using a variant and drop the base class is a good solution that may apply to your case.
Let's say you only have int, double and std::string:
using poly = std::variant<B<int>, B<double>, B<std::string>>;
std::array<poly, 3> arr;
arr[0] = B<int>{};
arr[1] = B<double>{};
arr[2] = B<std::string>{};
// arr[2] = B<widget>{}; // error, not in the variant type
std::visit(
[](auto& b) {
using T = std::decay_t<decltype(b)>;
if constexpr (std::is_same_v<B<int>, T>) {
b.Var = 2; // yay!
}
},
arr[0]
);
2b. Drop the base class and use generic functions
Drop the base class entirely, and template your functions that do operation on them. You can move all your function into an interface or many std::function. Operate on that instead of the function directly.
Here's an example of what I meant:
template<typename T>
void useA(T const& a) {
a.Var = 34; // Yay, direct access!
}
struct B {
std::function<void()> useA;
};
void createBWithInt() {
A<int> a;
B b;
b.useA = [a]{
useA(a);
};
};
This is fine for cases where you only have few operations. But it can quickly lead to code bloat if you have a lot of operations or if you have many types of std::function.
3. Use a visitor
You could create a visitor that dispatch to the right type.
This solution would be much close to what you except, but is quite combersome and can break easily when adding cases.
Something like this:
struct B_Details {
protected:
struct Visitor {
virtual accept(int) = 0;
virtual void accept(double) = 0;
virtual void accept(std::string) = 0;
virtual void accept(some_type) = 0;
};
template<typename T>
struct VisitorImpl : T, Visitor {
void accept(int value) override {
T::operator()(value);
}
void accept(double) override {
T::operator()(value);
}
void accept(std::string) override {
T::operator()(value);
}
void accept(some_type) override {
T::operator()(value);
}
};
};
template<typename T>
struct B : private B_Details {
template<typename F>
void visit(F f) {
dispatch_visitor(VisitorImpl<F>{f});
}
private:
virtual void dispatch_visitor(Visitor const&) = 0;
};
// later
B* b = ...;
b->visit([](auto const& Var) {
// Var is the right type here
});
Then of course, you have to implement the dispatch_visitor for each child class.
4. Use std::any
This is litteraly returning the variable with type erasure. You cannot do any operation on it without casting it back:
class A {
std::any GetVar()
};
I personnaly don't like this solution because it can break easily and is not generic at all. I would not even use polymorphism in that case.
I think it will be the easiest way. Just move the comparison method to the interface and override it in derived classes. Add the following lines to yor example:
class A
{
/*..................................................*/
virtual bool comp(const int) const { return false; }
virtual bool comp(const std::string) const { return false; }
virtual bool comp(const double) const { return false; }
};
template<class T>
class B : public A
{
/*..................................................*/
virtual bool comp(const T othr) const override { return othr == Var; }
};
void foo()
{
/*..................................................*/
if (i->comp(20))
{
/* do something*/
}
if (i->comp("Hello Stackoverflow"))
{
/* do something*/
}
/*..................................................*/
}

mixing templates with polymorphism

class A
{
friend void foo();
virtual void print_Var() const{};
};// does not contain variable Var;
template<class T>
class B : public A
{
T Var;
public:
B(T x):Var(x){}
void print_Var() const override
{
std::cout<<Var<<std::endl;
}
};
void foo()
{
std::array<std::unique_ptr<A>, 3> Arr = {
std::make_unique<B<int>>(100),
std::make_unique<B<int>>(20),
std::make_unique<B<std::string>>("Hello Stackoverflow")
};
std::shuffle(Arr.begin(), Arr.end(), std::mt19937(std::random_device()())); // 3rd parameter generated by Clang-Tidy
for (auto &i: Arr)
{
i->print_Var(); // OK
// auto z = i->Var // no member named Var in A
// obviously base class does not contain such variable
// if (i->Var==20) {/* do something*/}
// if (i->Var=="Hello Stackoverflow") {/* do something*/}
}
}
Explanation:
I want to iterate over array of pointers to A, which is filled with pointers to classes derived from A, and depending on what type is variable Var, do some if( ) statement.
Problem is that i cannot access Var, cause its not member of base class. However, it's possible to cout those values by, for example, overloaded function returning void. Could i write function in A class that returns templated type? like:
class A
{
<class T> GetVar()
}
Besides, I feel like I'm dealing with this problem in totally improper way. Can i mix templates and inheritance like that? If not, how should it be designed?
You have a few choices. I'll explain my preferred solution first.
1. Use dynamic dispatch
If you have an array of a base class type, why do you even want to do stuff with Var? That variable is specific to the child class. If you have a A somewhere, you shouldn't even care what B has or hasn't at that place.
Operations on the typed variable should be encapsulated in virtual function in the base class. If you want to do condition and stuff, maybe you could encapsulate that condition into a virtual function that returns a boolean.
2a. Drop the base class and use variant
Sometimes, you know in advance the amount of types that will go into that list. Using a variant and drop the base class is a good solution that may apply to your case.
Let's say you only have int, double and std::string:
using poly = std::variant<B<int>, B<double>, B<std::string>>;
std::array<poly, 3> arr;
arr[0] = B<int>{};
arr[1] = B<double>{};
arr[2] = B<std::string>{};
// arr[2] = B<widget>{}; // error, not in the variant type
std::visit(
[](auto& b) {
using T = std::decay_t<decltype(b)>;
if constexpr (std::is_same_v<B<int>, T>) {
b.Var = 2; // yay!
}
},
arr[0]
);
2b. Drop the base class and use generic functions
Drop the base class entirely, and template your functions that do operation on them. You can move all your function into an interface or many std::function. Operate on that instead of the function directly.
Here's an example of what I meant:
template<typename T>
void useA(T const& a) {
a.Var = 34; // Yay, direct access!
}
struct B {
std::function<void()> useA;
};
void createBWithInt() {
A<int> a;
B b;
b.useA = [a]{
useA(a);
};
};
This is fine for cases where you only have few operations. But it can quickly lead to code bloat if you have a lot of operations or if you have many types of std::function.
3. Use a visitor
You could create a visitor that dispatch to the right type.
This solution would be much close to what you except, but is quite combersome and can break easily when adding cases.
Something like this:
struct B_Details {
protected:
struct Visitor {
virtual accept(int) = 0;
virtual void accept(double) = 0;
virtual void accept(std::string) = 0;
virtual void accept(some_type) = 0;
};
template<typename T>
struct VisitorImpl : T, Visitor {
void accept(int value) override {
T::operator()(value);
}
void accept(double) override {
T::operator()(value);
}
void accept(std::string) override {
T::operator()(value);
}
void accept(some_type) override {
T::operator()(value);
}
};
};
template<typename T>
struct B : private B_Details {
template<typename F>
void visit(F f) {
dispatch_visitor(VisitorImpl<F>{f});
}
private:
virtual void dispatch_visitor(Visitor const&) = 0;
};
// later
B* b = ...;
b->visit([](auto const& Var) {
// Var is the right type here
});
Then of course, you have to implement the dispatch_visitor for each child class.
4. Use std::any
This is litteraly returning the variable with type erasure. You cannot do any operation on it without casting it back:
class A {
std::any GetVar()
};
I personnaly don't like this solution because it can break easily and is not generic at all. I would not even use polymorphism in that case.
I think it will be the easiest way. Just move the comparison method to the interface and override it in derived classes. Add the following lines to yor example:
class A
{
/*..................................................*/
virtual bool comp(const int) const { return false; }
virtual bool comp(const std::string) const { return false; }
virtual bool comp(const double) const { return false; }
};
template<class T>
class B : public A
{
/*..................................................*/
virtual bool comp(const T othr) const override { return othr == Var; }
};
void foo()
{
/*..................................................*/
if (i->comp(20))
{
/* do something*/
}
if (i->comp("Hello Stackoverflow"))
{
/* do something*/
}
/*..................................................*/
}

Mapping class types to other class types in C++

Given the following type hierarchy
class Base { public: virtual ~Base(); }
class OurDervied : public Base {}
class TheirDerived : public Base {}
class General { public: virtual ~General(); }
class MySpecial : public General {};
class YourSpecial : public General {};
I have a function f(Base *bp).
In f, I want to create an object with type that depends on the type passed in. For example, f creates a MySpecial when receiving an instance of OurDerived, and creates a YourSpecial when receiving an instance of TheirDerived.
I think I can do this with dynamic_cast. It probably requires trying to cast the received object repeatedly until a match is found (non-nullptr returned).
Another option is giving OurDerived, TheirDerived, etc a unique tag and then use a switch case construct to create MySpecial, YourSpecial, etc.
Are there any other options for mapping class types in C++?
Manual Type Switching
If the types you want to create have no common ancestor, you have no other option but use a
if (dynamic_cast<const DerivedA *>(&base))
{
// Create an object of some type.
}
else if (dynamic_cast<const DerivedB *>(&base))
{
// Create an object of some other type.
}
else if (dynamic_cast<const DerivedC *>(&base))
{
// Create an object of yet aother type.
}
else
{
// Handle the case that no type was matched. Maybe use a default or
// issue an error.
}
cascade and there is no direct way you can return the created object because a function cannot decide at run-time what return type it wants to have. The only way out would be to use type erasure or ugly unions.
Lookup Table with Factory Functions
Fortunately, this is not what you have to do if all the types you want to create are derived from a common base class, as you have indicated in the comments. In this case, you can map the typeid of an object to a factory function that creates the appropriate object. As usual with run-time polymorphism, this requires a heap allocation.
void
take_action(const Base& base)
{
using FactoryT = std::function<std::unique_ptr<General>()>;
static const std::map<std::type_index, FactoryT> factories {
{typeid(DerivedA), [](){ return std::make_unique<Special1>(); }},
{typeid(DerivedB), [](){ return std::make_unique<Special2>(); }},
{typeid(DerivedC), [](){ return std::make_unique<Special3>(); }},
};
const auto o_uptr = factories.at(typeid(base))();
// Use the object. It can also be returned.
}
I have made the std::map<std::type_index, std::function<FactoryT()>> static so it is created only once for the entire run-time of the program. It is not clear whether or not this is beneficial in your particular situation. Maybe benchmark it.
Here is a complete working example.
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <typeindex>
#include <typeinfo>
struct Base
{
virtual ~Base() = default;
virtual std::string
name() const
{
return "Base";
}
};
std::ostream&
operator<<(std::ostream& os, const Base& base)
{
return os << base.name();
}
template<char Token>
struct Derived : Base
{
virtual std::string
name() const override
{
std::string name {"Derived"};
name += Token;
return name;
}
};
using DerivedA = Derived<'A'>;
using DerivedB = Derived<'B'>;
using DerivedC = Derived<'C'>;
struct General
{
virtual ~General() = default;
virtual std::string
name() const
{
return "General";
}
};
template<char Token>
struct Special : General
{
virtual std::string
name() const override
{
std::string name {"Special"};
name += Token;
return name;
}
};
std::ostream&
operator<<(std::ostream& os, const General& general)
{
return os << general.name();
}
using Special1 = Special<'1'>;
using Special2 = Special<'2'>;
using Special3 = Special<'3'>;
void
take_action(const Base& base)
{
using FactoryT = std::function<std::unique_ptr<General>()>;
static const std::map<std::type_index, FactoryT> factories {
{typeid(DerivedA), [](){ return std::make_unique<Special1>(); }},
{typeid(DerivedB), [](){ return std::make_unique<Special2>(); }},
{typeid(DerivedC), [](){ return std::make_unique<Special3>(); }},
};
const auto o_uptr = factories.at(typeid(base))();
std::cout << base << " was mapped to " << *o_uptr << std::endl;
}
int
main()
{
take_action(DerivedA {});
take_action(DerivedB {});
take_action(DerivedC {});
return 0;
}
Output:
DerivedA was mapped to Special1
DerivedB was mapped to Special2
DerivedC was mapped to Special3
Visitor Pattern
Of course, you should ask yourself the question why you actually want to do this. There are for sure legitimate applications of this technique but taking an abstract type and then taking action based on its dynamic type is usually a sign of over-abstraction and makes for poorly maintainable code. Did you consider adding the factory directly to Base?
struct Base
{
virtual ~Base() = default;
virtual std::unique_ptr<General>
getDealer() = 0;
// ...
};
The Derived classes can then override getDealer to do what the factories lambdas did in the above example.
If this seems to intrusive (maybe the Base class shouldn't know anything about the General class at all), you could consider using the visitor pattern. It is a bit more work but allows for better decoupling. There is plenty of information available on this pattern so I'll only show its application to your specific problem and refer you to your favorite search engine if you need more explanation.
#include <iostream>
#include <memory>
#include <string>
struct BaseVisitor;
struct Base
{
virtual ~Base() = default;
virtual void
accept(BaseVisitor&) const = 0;
virtual std::string
name() const
{
return "Base";
}
};
std::ostream&
operator<<(std::ostream& os, const Base& base)
{
return os << base.name();
}
template<char Token>
struct Derived : Base
{
virtual void
accept(BaseVisitor& vtor) const override;
virtual std::string
name() const override
{
std::string name {"Derived"};
name += Token;
return name;
}
};
using DerivedA = Derived<'A'>;
using DerivedB = Derived<'B'>;
using DerivedC = Derived<'C'>;
struct BaseVisitor
{
virtual ~BaseVisitor() = default;
virtual void
visit(const DerivedA&) = 0;
virtual void
visit(const DerivedB&) = 0;
virtual void
visit(const DerivedC&) = 0;
};
// Cannot be defined earlier because we need the complete type of BaseVisitor.
template<char Token>
void
Derived<Token>::accept(BaseVisitor& vtor) const
{
vtor.visit(*this);
}
struct General
{
virtual ~General() = default;
virtual std::string
name() const
{
return "General";
}
};
template<char Token>
struct Special : General
{
virtual std::string
name() const override
{
std::string name {"Special"};
name += Token;
return name;
}
};
std::ostream&
operator<<(std::ostream& os, const General& general)
{
return os << general.name();
}
using Special1 = Special<'1'>;
using Special2 = Special<'2'>;
using Special3 = Special<'3'>;
void
take_action(const Base& base)
{
struct Mapper : BaseVisitor
{
std::unique_ptr<General> uptr {};
virtual void
visit(const DerivedA&) override
{
this->uptr.reset(new Special1 {});
}
virtual void
visit(const DerivedB&) override
{
this->uptr.reset(new Special2 {});
}
virtual void
visit(const DerivedC&) override
{
this->uptr.reset(new Special3 {});
}
};
Mapper visitor {};
base.accept(visitor);
std::cout << base << " was mapped to " << *visitor.uptr << std::endl;
}
int
main()
{
take_action(DerivedA {});
take_action(DerivedB {});
take_action(DerivedC {});
return 0;
}
Note how we have nicely broken the coupling between Base and General. On the down side, we had to introduce some kind of parent-to-child dependency via the BaseVisitor class.
This solution also gets completely rid of any explicit run-time type inference and elegantly lets the dynamic dispatch machinery do all the magic behind the scenes.
Yes, you can delegate type mapping to derived classes:
class Base
{
public:
virtual General* map() = 0;
};
class OurDerived: public Base
{
protected:
General* map()
{
// compute Type* for OurDerved
}
};
class TheirDerived: public Base
{
protected:
General* map()
{
// compute Type* for TheirDerived
}
};
It's hard to say without knowing what responsibilities your function has, or how you feel about coupling {My|Your}Special to {Our|Their}Derived.
Is Base constructible? Is Base or its derived classes allowed to have virtual methods? If you already incurred the cost of a vtable, I would delegate the responsibility to the derived types themselves, and explicitly make the method abstract on Base to force each derivation to explain itself in this regard.
Are MySpcial / YourSpecial related in the type hierarchy? Otherwise you are better off experimenting with explicit template instantiations of a helper function.