Здравствуйте, Marty, Вы писали:
R>>Единственная небольшая шероховатость — первый обработчик всегда вызывается последним (потому, что именно его результат возвращается). Но эта мелочь легко устраняется добавлением еще одного метода делегирования (аналогичного doDelegate):
Я выше упоминал о некрасивости, что первый обработчик вызыается последним. На самом деле у этой проблемы есть более элегантное решение, чем добаление еще одной перегрузки метода doDelegate. Исправить последовательность вызовов можно, использовав идиому RAII (см. класс AtExit и его использование в doDelegate). Следующий пример уже работает в точном соответствии с требованиями и в правильной последовательности, при этом все делегирование выполняется одним общим методом (doDelegate):
http://coliru.stacked-crooked.com/a/d66ee722f822d4fc
#include <functional>
#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;
}
};
struct AtExit
{
std::function<void()> guard;
~AtExit() { guard(); }
};
class Delegator : public IDelegationTest
{
template <typename F>
decltype(auto) doDelegate(F&& f)
{
const AtExit callTail {[&]
{
for (auto&& impl : m_tail)
{
f(*impl);
}
}};
return f(*m_head);
}
public:
template <typename T, typename...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);
}