Здравствуйте, Marty, Вы писали:
M>Здравствуйте!
M>Есть интерфейс, с какими-то виртуальными методами. Есть какие-то реализации этого интерфейса.
M>Есть отдельная реализация, которая хранит в себе указатели на несколько реализаций того же интерфейса, и каждый вызов метода через эту мульти реализацию должен вызывать этот метод через все хранящиеся указатели на другие реализации.
M>При этом, если метод что-то возвращает, то за результат берём вызов через первый хранящийся указатель на интерфейс, а остальное игнорируем
Ну, вот как-то так. Без явного указания прототипа с перегрузками, как ты и хотел. Единственная небольшая шероховатость — первый обработчик всегда вызывается последним (потому, что именно его результат возвращается). Но эта мелочь легко устраняется добавлением еще одного метода делегирования (аналогичного doDelegate):
http://coliru.stacked-crooked.com/a/3b8ca43b7a409e5f
#include <concepts>
#include <iostream>
#include <memory>
#include <vector>
struct IDelegationTest
{
virtual bool getter() = 0;
virtual bool setter(bool b) = 0;
virtual void jobImpl(bool b, int i) = 0;
virtual void jobImpl(bool b, int i, const std::string& s) = 0;
virtual int jobImpl2(bool b, int i) = 0;
};
struct DelegationTestImpl : public IDelegationTest
{
int n = 0;
DelegationTestImpl() = default;
explicit DelegationTestImpl(int n) : n(n) {}
virtual bool getter() override
{
std::cout << "DelegationTestImpl::getter(), n: " << n << "\n";
return true;
}
virtual bool setter(bool b) override
{
std::cout << "DelegationTestImpl::setter(bool b), b: " << b << ", n: " << n << "\n";
return true;
}
virtual void jobImpl(bool b, int i) override
{
std::cout << "DelegationTestImpl::jobImpl(bool b, int i), b: " << b << ", i: " << i << ", n: " << n << "\n";
}
virtual void jobImpl(bool b, int i, const std::string& s) override
{
std::cout << "DelegationTestImpl::jobImpl(bool b, int i), b: " << b << ", i: " << i << ", s: " << s << ", n: " << n << "\n";
}
virtual int jobImpl2(bool b, int i) override
{
std::cout << "DelegationTestImpl::jobImpl2(bool b, int i), b: " << b << ", i: " << i << ", n: " << n << "\n";
return n;
}
};
template <typename F>
concept DelegatorAgent = requires (F f, IDelegationTest& t)
{
f(t);
};
template <typename T>
concept DelegationTestPtr = std::convertible_to<std::decay_t<T>, std::shared_ptr<IDelegationTest>>;
class Delegator : public IDelegationTest
{
template <DelegatorAgent F>
decltype(auto) doDelegate(F&& f)
{
for (auto&& impl : m_tail)
{
f(*impl);
}
return f(*m_head);
}
public:
template <DelegationTestPtr T, DelegationTestPtr...X>
explicit Delegator(T&& head, X&&...tail)
: m_head(std::forward<T>(head)), m_tail{ std::forward<X>(tail)...} {}
bool getter() override { return doDelegate([&](IDelegationTest& t){ return t.getter(); }); }
bool setter(bool b) override { return doDelegate([&](IDelegationTest& t) { return t.setter(b); }); }
void jobImpl(bool b, int i) override { doDelegate([&](IDelegationTest& t) { t.jobImpl(b, i); }); }
void jobImpl(bool b, int i, const std::string& s) override { doDelegate([&](IDelegationTest& t) { t.jobImpl(b, i, s); }); }
int jobImpl2(bool b, int i) override { return doDelegate([&](IDelegationTest& t) { return t.jobImpl2(b, i); }); }
private:
using ImplPtr = std::shared_ptr<IDelegationTest>;
const ImplPtr m_head;
const std::vector<ImplPtr> m_tail;
};
int main()
{
Delegator delegator {
std::make_shared<DelegationTestImpl>(1),
std::make_shared<DelegationTestImpl>(2),
std::make_shared<DelegationTestImpl>(3),
};
delegator.getter();
delegator.setter(true);
delegator.jobImpl(false, 3);
delegator.jobImpl2(true, 5);
}