代码之家  ›  专栏  ›  技术社区  ›  Museful

如何替换给定类型中的模板参数?

  •  0
  • Museful  · 技术社区  · 7 年前

    假设一个模板参数调用 B 属于类型 C<D> (在实例化时),如何构造 C<A> ?

    以下是我的代码的一个最小化摘录:

    template<typename A>
    class foo {
        template<typename B> // B is guaranteed to always be of the form C<D>
        // How to write a function here with return type C<A>?
    }
    
    2 回复  |  直到 7 年前
        1
  •  7
  •   Tyker    7 年前

    你可以用 template specialization A的 template template parameter

    template<typename, typename>
    struct meta {};
    
    template<typename A, template<typename> typename C, typename B>
    struct meta<A, C<B>> {
        using type = C<A>;
    };
    

    meta<A, C<B>>::type C<A>

    如果要在基本情况下处理默认参数

    template<typename...>
    struct meta {};
    
    template<typename A, template<typename...> typename C, typename B, typename ... Ts>
    struct meta<A, C<B, Ts...>> {
        using type = C<A, Ts...>;
    };
    
        2
  •  1
  •   Yakk - Adam Nevraumont    7 年前

    首先,我们编写一些机制来替换模板类型实例中的类型:

    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> 使用默认参数。这个 模板类… 模式匹配接受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 .

    有可能我们会从递归替换中得到可怕的错误。 A 具有 B 在一个模板的其余参数中,但是如前所述,如果我们不这样做,我们肯定会对普通模板产生一些可怕的影响。