【发布时间】:2017-05-09 16:12:29
【问题描述】:
假设我们有以下三个结构。
struct T1
{
using type = std::tuple<A1, A2, A3>;
}
struct T2
{
using type = std::tuple<A1, A2>;
}
struct T3
{
using type = std::tuple<A1>;
}
然后我创建一个包含以下类型的实例的元组:
std::tuple<T1, T2, T3> types;
现在是棘手的部分 - 我将如何创建这样的元组
std::tuple<std::tuple<T1&, T2&, T3&>, std::tuple<T1&, T2&>, std::tuple<T1&>>
在“类型”元组中...
1) ... 第一个元组包含对嵌套 typedef 包含 A1 的所有元素的引用
2) ...第二个元组包含一个引用嵌套typedefs包含的所有元素A2
3) ...第三个元组包含一个引用嵌套typedefs包含A3的所有元素
编辑
我整理了一个我正在尝试做的小例子,请记住,这段代码还不能工作,但它应该让您更好地理解我正在尝试做的事情。
#include <iostream>
#include <tuple>
#include <type_traits>
#include <utility>
namespace util
{
template<typename Function, typename Tuple>
void for_each(Function&& function, Tuple&& tuple)
{
std::apply([&function](auto&&... xs){ (function(std::forward<decltype(xs)>(xs)), ...); }, std::forward<Tuple>(tuple));
}
}
namespace tl
{
template<typename T, typename Tuple>
struct tuple_contains;
template<typename T, typename Tuple, typename = std::make_index_sequence<std::tuple_size_v<Tuple>>>
struct tuple_index;
template<typename T, typename ...Ts>
struct tuple_contains<T, std::tuple<Ts...>>
: std::bool_constant<(std::is_same_v<T, Ts> || ...)>
{};
template<typename T, typename ...Ts, std::size_t ...Is>
struct tuple_index<T, std::tuple<Ts...>, std::index_sequence<Is...>>
: std::integral_constant<std::size_t, ((static_cast<std::size_t>(std::is_same_v<T, Ts>) * Is) + ...)>
{};
template<typename T, typename Tuple>
inline constexpr auto tuple_contains_v{ tuple_contains<T, Tuple>::value };
template<typename T, typename Tuple>
inline constexpr auto tuple_index_v{ tuple_index<T, Tuple>::value };
}
template<typename EventList>
class ObserverInterface;
template<typename ObserverList>
class ObserverManager;
template<typename EventList, typename ObserverList>
class EventManager;
template<typename T>
class EventHandler
{
public:
virtual void Receive(const T&) = 0;
};
template<typename ...Events>
class ObserverInterface<std::tuple<Events...>>
: public EventHandler<Events>...
{};
template<typename ...Observers>
class ObserverManager<std::tuple<Observers...>>
{
public:
template<typename T>
T& GetObserver() noexcept
{
return std::get<T>(observers_);
}
private:
std::tuple<Observers...> observers_;
};
template<typename ...Events, typename ...Observers>
class EventManager<std::tuple<Events...>, std::tuple<Observers...>>
{
public:
EventManager(ObserverManager<std::tuple<Observers...>>& observerManager)
: observerManager_{ observerManager }
{}
public:
template<typename T>
static constexpr bool isEvent{ tl::tuple_contains_v<T, std::tuple<Events...>> };
template<typename T>
static constexpr std::enable_if_t<isEvent<T>, std::size_t> eventIndex{ tl::tuple_index_v<T, std::tuple<Events...>> };
public:
template<typename T, typename ...Arguments>
std::enable_if_t<isEvent<T>> DispatchEvent(Arguments&&... arguments) noexcept
{
T event(std::forward<Arguments>(arguments)...);
util::for_each([&](auto&& observer){ observer.Receive(event); }, std::get<eventIndex<T>>(observers_));
}
private:
ObserverManager<std::tuple<Observers...>>& observerManager_;
std::tuple</* */> observers_;
};
struct EventOne
{
float value;
};
struct EventTwo
{
float value;
};
struct EventThree
{
float value;
};
class ObserverOne final
: public ObserverInterface<std::tuple<EventOne, EventTwo>>
{
public:
using Events = std::tuple<EventOne, EventTwo>;
void Receive(const EventOne& event) override
{
std::cout << "Received EventOne!\n";
}
void Receive(const EventTwo& event) override
{
std::cout << "Received EventTwo!\n";
}
};
class ObserverTwo final
: public ObserverInterface<std::tuple<EventTwo, EventThree>>
{
public:
using Events = std::tuple<EventTwo, EventThree>;
void Receive(const EventTwo& event) override
{
std::cout << "Received EventTwo!\n";
}
void Receive(const EventThree& event) override
{
std::cout << "Received EventThree!\n";
}
};
using MainEventList = std::tuple<EventOne, EventTwo, EventThree>;
using MainObserverList = std::tuple<ObserverOne, ObserverTwo>;
int main()
{
ObserverManager<MainObserverList> om;
EventManager<MainEventList, MainObserverList> em(om);
em.DispatchEvent<EventTwo>(10.f);
return 0;
}
现在事件管理器中的 'observers_' 元组还没有声明,因为那是我还不知道该怎么做的元组。
【问题讨论】:
-
这是一个奇怪的具体要求。也被严重低估(
tuple<T2, T1, T3>转换成什么?tuple<T2>呢?tuple<>?As 如何参与其中?)。 -
你有什么尝试?将
std::tuple<T1, T2>转换为std::tuple<T1::type, T2::type>似乎很容易。将std::tuple<A, B>转换为std::tuple<A&, B&>似乎也很容易。 -
这很痛苦。但是给定一个调试过的 TMP 库,将
tuple<Ts...>映射到tuple<tuple<Ts, Ts>...>,将tuple<tuple<K,V>>映射到tuple<tuple<K::type, V>...>,将tuple<tuple<K, V>...>过滤为Pred<K>,将tuple<tuple<K,V>...>映射到tuple<V...>,将tuple<T...>映射到 @9782 @,然后全部执行 3 次,其中Pred是tuple<Ts...>,其中有一个T0,其中T0不同于A1A2A3。然后制作一个元组的结果。
标签: c++ c++11 c++14 template-meta-programming c++17