Я не уверен, что полностью понимаю ваш вопрос, но если ваше ограничение для наблюдателей одного типа не является жестким, вы можете применить магию метапрограммирования для итерации списка типов и вызова статического update()
на каждом из них, без ручного развертывания.
Вот пример:
#include <iostream>
#include <tuple>
#include <utility>
// A list of types
template<typename... Ts> class observers{
template<std::size_t I, typename...>
struct at_impl{};
template<std::size_t I, typename T, typename... Others>
struct at_impl<I, T, Others...> {
using type = typename at_impl<I-1, Others...>::type;
};
template<typename T, typename... Others>
struct at_impl<0, T, Others...> {
using type = T;
};
public:
// A way of getting the nth-type listed
template<std::size_t I>
using at = typename at_impl<I, Ts...>::type;
constexpr inline static std::size_t size = sizeof...(Ts);
};
// Our notification function will iterate a list of observers, and call update() on each one.
template<typename ObserverList, std::size_t I = 0>
std::enable_if_t< ObserverList::size <= I, void>
notify_impl(int v) {}
template<typename ObserverList, std::size_t I = 0>
std::enable_if_t< I < ObserverList::size, void>
notify_impl(int v) {
using T = typename ObserverList::template at<I>;
T::update(v);
notify_impl<ObserverList, I+1>(v);
}
template<typename ObserverList>
void notify(int v) {
notify_impl<ObserverList, 0>(v);
}
// Let's define some observers...
struct FirstObserver {
static void update(int v){std::cout << "first observer notified with value = " << v << '\n';}
};
struct SecondObserver {
static void update(int v){std::cout << "second observer notified with value = " << v << '\n';}
};
struct ThirdObserver {
static void update(int v){std::cout << "third observer notified with value = " << v << '\n';}
};
// ... and put those observers on a list.
using ObserverList = observers<FirstObserver, SecondObserver, ThirdObserver>;
int main() {
notify<ObserverList>(0);
}
Вывод:
first observer notified with value = 0
second observer notified with value = 0
third observer notified with value = 0
Однако, если вы просто хотите вызвать Observer::update
итеративно, вы можете просто реализовать notify
следующим образом:
template<typename T, std::size_t I, std::size_t MAX>
std::enable_if_t< MAX <= I, void>
notify_impl(decltype(T::value)) {}
template<typename T, std::size_t I, std::size_t MAX>
std::enable_if_t< I < MAX, void>
notify_impl(decltype(T::value) v) {
Observer::update<T, I>(v);
notify_impl<T, I+1, MAX>(v);
}
template<typename T>
void notify(decltype(T::value) v) {
// Assuming we have 3 observers
notify_impl<T, 0, 3>(v);
}
Если вы беспокоитесь о том, что происходит на разныхединицы преобразования, вам просто нужно помнить, что шаблоны являются генераторами кода: в конечном счете, сгенерированный код будет таким же, как если бы вы выполняли развернутый цикл вручную, и, если это работает, это должно работать также.