首先我们编写一些机制来替换模板类型实例中的类型:
template<class In, class Replace>
struct replace_first_type;
template<template<class...>class Z, class T0, class...Ts, class Replace>
struct replace_first_type<Z<T0, Ts...>, Replace> {
using type=Z<Replace, Ts...>;
};
template<class In, class Replace>
using replace_first = typename replace_first_type<In,Replace>::type;
replace_first< Z, X > 接受Z,模式将其与任何template<class...> 匹配,获取第一个参数,并将其替换为X。
这不适用于std::array<int, 7>,因为7 不是类型,但适用于std::vector<int>; vector 实际上是带有默认参数的 <T, A>。 template<class...> 模式匹配包含 0 个或更多类的模板。
然后我们应用它:
template<typename A>
class foo {
template<typename B>
using result = replace_first<B, A>;
};
现在foo<int>::template result< std::vector<double> > 是std::vector<int, std::alloctor<double>>。诚然,这是一种非常愚蠢的类型。
如果你有一个函数:
template<class B>
result<B> do_something() {
return {};
}
实际上返回该类型的值。
我们可以通过递归替换我们替换的类型来解决上面std::allocator<double>的问题...
template<class X, class Src, class Dest>
struct subst_type {
using type=X;
};
template<class X, class Src, class Dest>
using subst_t = typename subst_type<X, Src, Dest>::type;
template<template<class...>class Z, class...Ts, class Src, class Dest>
struct subst_type<Z<Ts...>, Src, Dest> {
using type=Z<subst_t<Ts, Src, Dest>...>;
};
template<class Src, class Dest>
struct subst_type<Src, Src, Dest> {
using type=Dest;
};
并先申请替换:
template<class In, class Replace>
struct replace_first_type;
template<template<class...>class Z, class T0, class...Ts, class Replace>
struct replace_first_type<Z<T0, Ts...>, Replace> {
using type=Z<Replace, subst_t<Ts, T0, Replace>...>;
};
现在当我们foo<int>::result<std::vector<double>> 时,我们得到std::vector<int, std::allocator<int>> 而不是std::vector<int, std::allocator<double>>(这是一个无用的类型)。
Live example.
在模板的其余参数中递归地用B 替换A 可能会出现严重错误,但如前所述,如果我们不这样做,我们肯定会在使用通用模板时遇到一些可怕的问题'不要这样做。