创建对满足特定谓词的对象的引用元组

时间:2017-05-09 16:12:30

标签: c++ c++11 c++14 template-meta-programming c++17

我们假设我们有以下三种结构。

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)...第二个元组包含一个引用所有嵌套typedef包含A2

的元素

3)...第三个元组包含一个引用所有嵌套typedef包含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_'元组还没有被声明,因为那是我无法弄清楚如何去做的元组。

1 个答案:

答案 0 :(得分:1)

template<class Tag>
using type_t = typename Tag::type;
template<class T> struct tag_t{using type=T; constexpr tag_t(){}};
template<class T> constexpr tag_t<T> tag{};

template<template<class...>class Z, class Tuple>
struct fmap_tuple {};
template<template<class...>class Z, class Tuple>
using fmap_tuple_t = type_t<fmap_tuple<Z,Tuple>>;

template<template<class...>class Z, class...Ts>
struct fmap_tuple<Z, std::tuple<Ts...>>:
    tag_t<std::tuple<Z<Ts>...>>
{};

template<template<class...>class Z>
struct fmapper {
  template<class Tuple>
  using result=fmap_tuple_t<Z, Tuple>;
};

template<class...Tuples>
using cat_tuples = decltype(std::tuple_cat( std::declval<Tuples>()... ));

template<template<class...>class Z, class Tuple, class=void>
struct filter;
template<template<class...>class Z, class Tuple>
using filter_t = type_t<filter<Z,Tuple>>;

template<template<class...>class Z>
struct filter<Z, std::tuple<>,void>:tag_t<std::tuple<>>{};
template<template<class...>class Z, class T0, class...Ts>
struct filter<Z, std::tuple<T0, Ts...>, std::enable_if_t<Z<T0>::value>>:
    tag_t<
        cat_tuples<
            std::tuple<T0>,
            filter_t<Z, std::tuple<Ts...>>
        >
    >
{};
template<template<class...>class Z, class T0, class...Ts>
struct filter<Z, std::tuple<T0, Ts...>, std::enable_if_t<!Z<T0>::value>>:
    filter<Z, std::tuple<Ts...>>
{};

template<template<class...>class Z0, template<class...>class...Zs>
struct cat_Zs {
private:
    template<class...Ts>
    using Zs_result = typename cat_Zs<Zs...>::template result<Ts...>;
public:
    template<class...Ts>
    using result= Z0<Zs_result<Ts...>>;
};

template<template<class...>class Z0>
struct cat_Zs<Z0> {
    template<class...Ts> using result=Z0<Ts...>;
};

template<class T>
struct is_T {
    template<class U>
    using result = std::is_same<T,U>;
};

template<template<class...>class Test>
struct everything_fails_test {
    template<class Tuple>
    using result = std::is_same< std::tuple<>, filter_t<Test, Tuple> >;
};
template<template<class...>class Test>
struct has_test_passer {
    template<class Tuple>
    using result = std::integral_constant<bool,
        !everything_fails_test<Test>::template result<Tuple>::value
    >;
};

template<class T>
using lacks_T = everything_fails_test< is_T<T>::template result >;
template<class T>
using contains_T = has_test_passer< is_T<T>::template result >;


template<template<class...>class Z, class Tuple>
struct make_kv;
template<template<class...>class Z, class Tuple>
using make_kv_t = type_t<make_kv<Z,Tuple>>;

template<template<class...>class Z, class...Ts>
struct make_kv<Z,std::tuple<Ts...>>:tag_t<
    std::tuple< std::tuple<Ts, Z<Ts>>... >
>{};

template<class Tuple>
struct get_k;
template<class Tuple>
using get_k_t=type_t<get_k<Tuple>>;
template<class K, class V>
struct get_k<std::tuple<K,V>>:tag_t<K>{};
template<class Tuple>
struct get_v;
template<class...Tuple>
using get_v_t=type_t<get_v<Tuple...>>;
template<class K, class V>
struct get_v<std::tuple<K,V>>:tag_t<V>{};

template<class Tuple>
using step1 =  make_kv_t< type_t, Tuple >;

template<class T>
using value_has_T = cat_Zs<contains_T<T>::template result,get_v_t>;

template<class Tuple, class T>
using step2 = filter_t<
      value_has_T<T>::template result
    ,step1< Tuple >
>;
template<class Tuple, class T>
using step3 = fmap_tuple_t<
    get_k_t,
    step2<Tuple, T>
>;
template<class Tuple, class...Targets>
using solution_base = std::tuple<
    fmap_tuple_t<
        std::add_lvalue_reference_t,
        step3<Tuple, Targets>
    >...
>;

struct A1{};
struct A2{};
struct A3{};

template<class Tuple>
using solution = solution_base<Tuple, A1, A2, A3>;

struct T1
{
    using type = std::tuple<A1, A2, A3>;
};

struct T2
{
    using type = std::tuple<A1, A2>;
};

struct T3
{
    using type = std::tuple<A1>;
};

using input = std::tuple<T1, T2, T3>;

using answer = std::tuple<std::tuple<T1&, T2&, T3&>, std::tuple<T1&, T2&>, std::tuple<T1&>>;
static_assert( std::is_same<answer, solution<input> >::value, "works" );

或类似的东西。

live example

我们在这里定义了一些原语 - fmap_tuple_tfilter_tfmappercat_tuplescat_Zshas_test_passer,{{1} },make_kv_tget_v_t

然后我们用这些原语构建一个类型表达式。