鉴于
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
包等,该怎么办?
答案 0 :(得分:0)
以下解决方案对我来说是半满意的。现在至少将所有不同类型的模板均匀化为类型,并且现在满足特定的静态断言。如果有人可以指导我如何在int
的最后部分专业化中概括change_templates
,则可能会删除&#34;不可维护的&#34; 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...>
需要对其他整数类型重复。