避免无限模板实例化

时间:2015-10-20 02:09:53

标签: c++ templates c++11 recursion variadic

鉴于

struct A {};
struct B { using links = std::tuple<A>; };
struct C { using links = std::tuple<A,B>; };
struct D { using links = std::tuple<C>; };
struct E { using links = std::tuple<D>; };
struct F { using links = std::tuple<D>; };
struct G { using links = std::tuple<D>; };
struct H { using links = std::tuple<E,F,G>; };

AllLinksFrom<H>将是std::tuple<A,B,C,D,E,F,G,H>(字母的顺序无关紧要),因为H与E,F和G相关联,而E,F和G又与其他类相关联,而其他类依次链接到其他类链接到其他类,依此类推,直到获得所有链接的链接...并且所有这些类的联合。

我已经解决了这个问题,但是如果我改变了,那么我的解决方案会崩溃,

struct E { using links = std::tuple<D>; };

struct E { using links = std::tuple<D,H>; };

因为通过将E链接回H,我得到了无限递归(使用我当前的算法)。在这种情况下,输出仍然应该是相同的(即std::tuple<A,B,C,D,E,F,G,H>)。有人可以建议如何解决这个问题吗?

如果您想要写出完整的解决方案,可以借用Unionhas_links_member的代码(经测试可正常工作)以节省时间:

template <typename T>
struct Identity { using type = T; };

// ExistsInPack
template <typename T, typename Pack> struct ExistsInPack;

template <typename T, template <typename...> class P>
struct ExistsInPack<T, P<>> : std::false_type {};

template <typename T, template <typename...> class P, typename First, typename... Rest>
struct ExistsInPack<T, P<First, Rest...>> : ExistsInPack<T, P<Rest...>> {};

template <typename T, template <typename...> class P, typename... Rest>
struct ExistsInPack<T, P<T, Rest...>> : std::true_type {};

// Union of packs.
template <typename, typename, typename> struct UnionHelper;

template <template <typename...> class P, typename... Types, typename... Accumulated>
struct UnionHelper<P<Types...>, P<>, P<Accumulated...>> {
    using type = P<Accumulated...>;
};

template <template <typename...> class P, typename First, typename... Rest, typename... Types, typename... Accumulated>
struct UnionHelper<P<Types...>, P<First, Rest...>, P<Accumulated...>> : std::conditional_t<ExistsInPack<First, P<Types...>>::value,
        UnionHelper<P<Types...>, P<Rest...>, P<Accumulated...>>,
        UnionHelper<P<Types...>, P<Rest...>, P<Accumulated..., First>>
    > {};

template <typename...> struct Union;

template <>
struct Union<> { using type = void; };

template <typename Pack>
struct Union<Pack> : Identity<Pack> {};

template <typename Pack1, typename Pack2>
struct Union<Pack1, Pack2> : UnionHelper<Pack1, Pack2, Pack1> {};

template <typename Pack1, typename Pack2, typename... Packs>
struct Union<Pack1, Pack2, Packs...> : Union<typename Union<Pack1, Pack2>::type, Packs...> {};

// Detecting if the member type T::links exists in class T.
template <typename T>
using void_t = void;

template <typename T, typename = void>
struct has_links_member : std::false_type {};

template <typename T>
struct has_links_member<T, void_t<typename T::links>> : std::true_type {};

// LinkedTypes<T> is T::links if such a member type exists in T, else it is std::tuple<>.
template <typename T, bool HasLinksMember>
struct LinkedTypesHelper : Identity <typename T::links> {};

template <typename T>
struct LinkedTypesHelper<T, false> : Identity <std::tuple<>> {};

template <typename T>
using LinkedTypes = typename LinkedTypesHelper<T, has_links_member<T>::value>::type;

如果你想看到它,这是我目前的完整解决方案(仅适用于第一个例子):http://ideone.com/efKFRo

0 个答案:

没有答案