更改包的模板
Changing templates for packs
给定
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...>
需要对其他积分类型重复。
相关文章:
- 没有找到相关文章