У меня есть вопрос об использовании функций-друзей внутри вложенного полиморфного класса для получения информации о типах.
У меня есть следующий код, который демонстрирует, что я делаю.Учитывая два класса, A<T>
и B<T>
, я могу создать полиморфную оболочку во время выполнения, которая содержит A
или B
.На практике эта оболочка может содержать все, что угодно, в том числе другой шаблонный класс с аналогичным статическим интерфейсом.
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';
}
};
Оболочка основана на концепциях полиморфизма времени выполнения Шона Родителя, но мне нужно получить информацию о типе длянекоторые операции.Например, может быть, я могу добавить A
и B
, но не A
и C
.По сути, если я помещаю функцию Friend в шаблонный класс-оболочку, я могу привести объект обратно к его исходному типу.
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);
}
};
Обратите внимание, что я могу static_cast
класс Concept
вфункция Friend, потому что ее тип может быть выведен из контекста класса Model<T>
.
Так что я могу использовать такой код:
Wrapper a(1);
B<int> b{2};
someFriend(a, b);
Какие выходные данные:
Hello from A! 1
Hello from B! 2
3
Мой вопрос заключается в том, есть ли какая-то непредвиденная проблема, связанная с такими действиями.Кроме того, если я заменю объект, удерживаемый в указателе, static_cast
все еще будет работать?
Некоторые предварительные тесты, которые я провел, показывают, что это довольно надежно, но я иногда сталкиваюсь с проблемой, что вызов, кажется, «специализируется» вокруг первого объекта и затем не переключается, если указатель меняется нановый объект.
Здесь - ссылка на код.