Рассмотрим следующий минимальный (но полный) пример C ++ 17:
#include <iostream>
#include <memory>
class Parent {
public:
Parent() = default;
};
class Child : public Parent {
public:
Child() : Parent() {};
};
template <class T> class Sink;
template <class T> class Source {
template <class O> friend class Sink;
public:
Source() = default;
void operator>=(std::shared_ptr<Sink<T>> sink) {
m_sink = sink;
sink->m_source = this;
}
template <class MORPH>
typename std::enable_if_t<std::is_base_of<Sink<T>, MORPH>::value, void>
operator>=(std::shared_ptr<MORPH> sink) {
return *this >= std::static_pointer_cast<Sink<T>>(sink);
}
private:
std::shared_ptr<Sink<T>> m_sink;
};
template <class T> class Sink {
template <class O> friend class Source;
public:
Sink() = default;
private:
Source<T> *m_source = nullptr;
};
int main(int argc, char *argv[]) {
Source<Child> source;
std::shared_ptr<Sink<Parent>> sink;
source >= sink;
return 0;
}
Я пытаюсь сделать здесь основную c архитектуру канала и фильтра.
Существуют типы Source
и Sink
(для простоты нет каналов), и они связаны через оператор >=
.
При создании источника и приемника, которые специализируются на одном типе, все Это хорошо. Но когда источник генерирует объекты типов, которые наследуются от базового класса (как показано в примере), и приемник принимает такие родительские типы, вещи взрываются.
Короче говоря, будет работать следующее:
Source<Child> source;
std::shared_ptr<Sink<Child>> sink;
но я хотел бы принять расширенный набор типов в приемнике.
Кроме того, я хочу иметь возможность связывать типы, также наследуемые от Sink
, таким образом, шаблон MORPH
Требуется перегрузка оператора. Сейчас это прекрасно работает для меня (до тех пор, пока используется тот же параметр T).
Пока я придумал грязный хак:
template <class T_>
typename std::enable_if_t<std::is_base_of<T_, T>::value, void>
operator>=(std::shared_ptr<Sink<T_>> sink) {
m_sink = std::shared_ptr<Sink<T>>(reinterpret_cast<Sink<T>*>(sink.get()));
sink->m_source = reinterpret_cast<Source<T_>*>(this);
}
...
template <class T_, template <class> class MORPH>
typename std::enable_if_t<std::is_base_of<T_, T>::value && std::is_base_of<Sink<T_>, MORPH<T_>>::value, void>
operator>=(std::shared_ptr<MORPH<T_>> sink) {
return *this >= std::static_pointer_cast<Sink<T_>>(sink);
}
Это меня утомляет по двум причинам:
- Необходимо заново создать shared_ptr, чтобы иметь возможность назначить его
m_sink
- Все
reinterpret_cast
в необработанных указателях в соответствии с шаблоном типы T
и T_
Есть ли лучший способ достичь sh того, к чему я стремлюсь?