I have a question about using friend functions inside a nested polymorphic class to retrieve type information.
I have the following code which demonstrates what I'm doing. Given two classes, A<T>
and B<T>
, I can create a runtime polymorphic wrapper that holds an A
or B
. In practice, this wrapper could hold anything, including another templated class that has a similar static interface.
template<typename T>
struct A {
T value_;
A(T value) : value_(value) {}
void sayHello() const {
std::cout << "Hello from A! " << value_ << '\n';
}
};
template<typename T>
struct B {
T value_;
B(T value) : value_(value) {}
void sayHello() const {
std::cout << "Hello from B! " << value_ << '\n';
}
};
The wrapper comes from Sean Parent's Runtime Polymorphism concepts, but I have a need to retrieve the type information for some operations. For example, maybe I can add an A
and a B
, but not an A
and a C
. Basically, if I place a friend function within the templated wrapper class, I can cast the object back to its original type.
class Wrapper {
private:
class Concept {
public:
virtual ~Concept() = default;
virtual void sayHello() const = 0;
};
template<typename T>
class Model final
: public Concept {
private:
T data_;
public:
Model(T data) : data_(data) {}
virtual void sayHello() const override {
data_.sayHello();
}
private:
template<typename U>
friend inline void doSomething(const Concept &lhs, const B<U> &rhs) {
T x = static_cast<const Model<T> &>(lhs).data_;
x.sayHello();
rhs.sayHello();
auto y = x.value_ + rhs.value_;
std::cout << y << '\n';
}
};
template<typename U>
friend inline void doSomething(const Concept &lhs, const B<U> &rhs);
std::shared_ptr<const Concept> ptr_;
public:
template<typename T>
explicit inline Wrapper(T a)
: ptr_(std::make_shared<Model<A<T>>>(std::move(a))) {}
template<typename U>
friend inline void someFriend(Wrapper &lhs, B<U> &rhs) {
doSomething(*lhs.ptr_, rhs);
}
};
Note that I'm able to static_cast
the Concept
class within the friend function because its type can be deduced from within the context of the Model<T>
class.
So I can use the code like this:
Wrapper a(1);
B<int> b{2};
someFriend(a, b);
Which outputs:
Hello from A! 1
Hello from B! 2
3
My question is whether there is some kind of unforeseen problem doing things this way. Also, if I replace the object held in the pointer, should the static_cast
still work?
Some preliminary tests I've run show that it's fairly reliable, but I occasionally run into the problem that the call seems to 'specialize' around the first object and then doesn't switch if the pointer changes to a new object.
Here is a link to the code.
Aucun commentaire:
Enregistrer un commentaire