更改包的模板

Changing templates for packs

本文关键字:      更新时间:2023-10-16

给定

template <typename...> class P;  template <typename...> class Q;
template <typename...> class R;  template <typename...> class S;

让我们定义,change_templates如下例所示:

change_templates<P<int, char, R<double, int>, bool>, P,Q, R,S>::type

是要

Q<int, char, S<double, int>, bool>

更一般地说,

change_templates<P<int, Q<int, int>, char, P<double, P<char, char>, int>, bool>, P,Q, P,R, Q,S>::type

是要

Q<int, S<int, int>, char, R<double, P<char, char>, int>, bool>

(请注意,缺少第三个P,...对意味着第三个P保持不变,尽管无论如何都可以使用P,P)。 好消息是我让它与以下内容一起工作:

#include <iostream>
#include <type_traits>
template <template <typename...> class...> struct TP;
template <template <typename...> class, typename Templates, typename Checked = TP<>> struct find_template;
template <template <typename...> class P, template <typename...> class Q,
    template <typename...> class... Rest, template <typename...> class... Checked>
struct find_template<P, TP<Q, Rest...>, TP<Checked...>> :
    find_template<P, TP<Rest...>, TP<Checked..., Q>> {};  // Search the next template by default.
template <template <typename...> class P, template <typename...> class Q,
    template <typename...> class... Rest, template <typename...> class... Checked>
struct find_template<P, TP<P, Q, Rest...>, TP<Checked...>> {  // Q follows P, which means that P is to change to Q.
    template <typename... Ts>
    using type = Q<Ts...>;
    using remaining_templates = TP<Checked..., Rest...>;  // Every template except P,Q kept for later searches, since they have been used now.
};
template <template <typename...> class P, template <typename...> class... Checked>
struct find_template<P, TP<>, TP<Checked...>> {  // P not found.
    template <typename... Ts>
    using type = P<Ts...>;  // P not found, so simply don't change P.
    using remaining_templates = TP<Checked...>;
};
template <typename T, template <typename...> class... Templates>
struct change_templates {
    using type = T;  // Base case.  A non-pack type remains unchanged.
};
template <typename T, typename Templates> struct change_templates_impl;
template <typename T, template <typename...> class... Templates>
struct change_templates_impl<T, TP<Templates...>> :
    change_templates<T, Templates...> {};
template <template <typename...> class P, typename... Ts, template <typename...> class... Templates>
struct change_templates<P<Ts...>, Templates...> {  // A pack of types (possibly of other packs).
    using F = find_template<P, TP<Templates...>>;
    using Remaining = typename F::remaining_templates;  // To be passed on for the next find_template call.
    using type = typename F::template type<typename change_templates_impl<Ts, Remaining>::type...>;  // Recursive call.
};
// Testing
template <typename...> class P;  template <typename...> class Q;
template <typename...> class R;  template <typename...> class S;
int main() {
    static_assert (std::is_same<change_templates<P<int, char, double>, P, Q>::type, Q<int, char, double>>::value, "");
    static_assert (std::is_same<
        change_templates<P<int, char, R<double, int>, bool>, P,Q, R,S>::type,
        Q<int, char, S<double, int>, bool>
    >::value, "");
    static_assert (std::is_same<
        change_templates<P<int, Q<int, int>, char, P<double, P<char, char>, int>, bool>, P,Q, P,R, Q,S>::type,  // The third P in the pack is unchanged because there is no pair for the third P.
        Q<int, S<int, int>, char, R<double, P<char, char>, int>, bool>
    >::value, "");
}

但现在我自然想要以下内容:

template <int...> class I;  template <int...> class J;
int main() {
    static_assert (std::is_same<
        change_templates<P<int, char, I<4,5>, bool>, P,Q, I,J>::type,
        Q<int, char, J<4,5>, bool>
    >::value, "");
}

但是我不知道如何调整我上面的代码来处理这个问题,因为 P,Q 是类型的模板,而 I,J 是 int 的模板(或者更一般地说是任何整数类型的模板)。 有没有办法使不同类型的模板同质化,以便上述模板按预期工作(或语法略有不同)? 如果我们同时拥有一包int和一包std::size_t,等等......在同一个包里?

以下解决方案对我来说是半满意的。 至少所有不同类型的模板现在都同质化为类型,并且现在满足了特定的静态断言。 如果有人可以指导我如何在change_templates的最后一个部分专业化中概括int,它可能会消除Murat Karakus评论的解决方案的"不可维护"方面。

#include <iostream>
#include <type_traits>
#include <tuple>
template <template <typename...> class...> struct K;
template <typename T, template <T...> class...> struct L;
template <typename Find, typename Templates, typename Checked = std::tuple<>> struct find_template;
template <typename FindMe, template <typename...> class Z, typename Mismatch, typename... Rest, typename... Checked>
struct find_template<FindMe, Z<Mismatch, Rest...>, Z<Checked...>> : find_template<FindMe, Z<Rest...>, Z<Checked..., Mismatch>> {};  // Search the next template by default.
template <template <typename...> class P, template <typename...> class Z, template <typename...> class Q, typename... Rest, typename... Checked>
struct find_template<K<P>, Z<K<P,Q>, Rest...>, Z<Checked...>> {  // Q follows P, which means that P is to change to Q.
    template <typename... Ts>
    using type = Q<Ts...>;
    using remaining_templates = Z<Checked..., Rest...>;  // Every template except P,Q kept for later searches, since they have been used now.
};
template <typename T, template <T...> class P, template <typename...> class Z, template <T...> class Q, typename... Rest, typename... Checked>
struct find_template<L<T,P>, Z<L<T,P,Q>, Rest...>, Z<Checked...>> {  // Q follows P, which means that P is to change to Q.
    template <T... Is>
    using type = Q<Is...>;
    using remaining_templates = Z<Checked..., Rest...>;  // Every template except P,Q kept for later searches, since they have been used now.
};
template <template <typename...> class P, template <typename...> class Z, typename... Checked>
struct find_template<K<P>, Z<>, Z<Checked...>> {  // P not found.
    template <typename... Ts>
    using type = P<Ts...>;  // P not found, so simply don't change P.
    using remaining_templates = Z<Checked...>;
};
template <typename T, typename... Templates>
struct change_templates {
    using type = T;  // Base case.  A non-pack type remains unchanged.
};
template <typename T, typename Templates> struct change_templates_impl;
template <typename T, template <typename...> class Z, typename... Templates>
struct change_templates_impl<T, Z<Templates...>> : change_templates<T, Templates...> {};
template <template <typename...> class P, typename... Ts, typename... Templates>
struct change_templates<P<Ts...>, Templates...> {  // A pack of types (possibly of other packs).
    using F = find_template<K<P>, std::tuple<Templates...>>;
    using Remaining = typename F::remaining_templates;  // To be passed on for the next find_template call.
    using type = typename F::template type<typename change_templates_impl<Ts, Remaining>::type...>;  // Recursive call.
};
template <template <int...> class P, int... Is, typename... Templates>
struct change_templates<P<Is...>, Templates...> {  // A pack of integral non-types.
    using F = find_template<L<int,P>, std::tuple<Templates...>>;
    using type = typename F::template type<Is...>;  // Non-recursive call, since the Is... cannot themselves be packs.
};
// Testing
template <typename...> class P;  template <typename...> class Q;
template <typename...> class R;  template <typename...> class S;
template <int...> class I;  template <int...> class J;
int main() {
    static_assert (std::is_same<change_templates<P<int, char, double>, K<P,Q>>::type, Q<int, char, double>>::value, "");
    static_assert (std::is_same<
        change_templates<P<int, char, R<double, int>, bool>, K<P,Q>, K<R,S>>::type,
        Q<int, char, S<double, int>, bool>
    >::value, "");
    static_assert (std::is_same<
        change_templates<P<int, Q<int, int>, char, P<double, P<char, char>, int>, bool>, K<P,Q>, K<P,R>, K<Q,S>>::type,  // The third P in the pack is unchanged because there is no K pair for the third P.
        Q<int, S<int, int>, char, R<double, P<char, char>, int>, bool>
    >::value, "");
    static_assert (std::is_same<
        change_templates<P<int, char, I<4,5>, bool>, K<P,Q>, L<int,I,J>>::type,
        Q<int, char, J<4,5>, bool>
    >::value, "");
}

更新:我意识到无法泛化 int,就像任何编译器都可以从函数中推断出T一样

template <typename T, template <T...> class P, T... Is>
T foo(P<Is...>);

所以

template <template <int...> class P, int... Is, typename... Templates>
struct change_templates<P<Is...>, Templates...>

需要对其他积分类型重复。

相关文章:
  • 没有找到相关文章