【问题标题】:Use default template parameter of one template declaration in another在另一个模板声明中使用一个模板声明的默认模板参数
【发布时间】:2020-09-01 15:25:11
【问题描述】:

假设我有一个带有一些默认模板参数的类模板cls1 和另一个使用cls1 的类模板cls2

template<typename T1, typename T2 = int, typename U = std::vector<T1>>
class cls1 {};

template<typename T1, typename T2 = int, typename U = std::vector<T1>>
class cls2 : public cls1<T1, T2, U> {};

现在,如果我想更改 cls1 的某些模板参数的默认值,我还需要手动cls2 中更改它以保持一致性。

我已经考虑过使用类型别名(或在非类型模板参数的情况下使用constexpr 变量):

using cls1_default_t_2 = int;
template<typename T1>
using cls1_default_u = std::vector<T1>;

template<typename T1, typename T2 = cls1_default_t_2, typename U = cls1_default_u_t<T1>>
class cls1 {};

template<typename T1, typename T2 = cls1_default_t_2, typename U = cls1_default_u_t<T1>>
class cls2 : public cls1<T1, T2, U> {};

现在我只需要更改cls1_default_t_2cls1_default_u

但是,这有点冗长,具体取决于默认参数的数量。此外,如果我现在想使另一个类模板cls3 使用cls2,则不宜使用cls1 的默认参数,因为cls1 实际上并没有被cls3 直接使用。相反,我需要再次为cls2 的默认模板参数提供类型别名(和constexprs),以便在cls3 中使用它们:

// ... cls1 as seen above

using cls2_default_t_2 = cls1_default_t_2;
template<typename T1>
using cls2_default_u_t = cls1_default_u_t<T1>;

template<typename T1, typename T2 = cls2_default_t_2, typename U = cls2_default_u_t<T1>>
class cls2 : public cls1<T1, T2, U> {};

template<typename T1, typename T2 = cls2_default_t_2, typename U = cls2_default_u_t<T1>>
class cls3 : public cls2<T1, T2, U> {};

那么,有没有更简洁的表示法在另一个模板声明中使用默认模板参数?

【问题讨论】:

  • 你需要很多默认类型吗?你不能只做using default_type = int; using default_container = std::vector&lt;int&gt;; 并使用它吗?
  • @idclev463035818 因为那时,如果我有cls3 使用default_type 并更改cls2 的默认参数,cls3 不会反映此显式更改。我想像template&lt;typename T1, typename T2 = [default of cls2's T2], typename U = [default of cls2's U]&gt;cls3 (分别为cls2)。

标签: c++ templates default-arguments


【解决方案1】:

我认为没有办法完全避免冗长。与函数默认参数类似,如果不付出额外的努力,您将无法真正掌握模板默认参数。这是我能想到的最好的:

template<typename T1, typename T2 = int, typename U = std::vector<T1>>
class cls1 {
    using value_type = T2;
    using container_type = U;
};

template<typename T1, 
         typename T2 = typename cls1<T1>::value_type, 
         typename U = typename cls1<T1>::container_type>
class cls2 : public  cls1<T1, T2, U> {};

拥有别名不仅对默认参数有益,因此也许这并不是真正的“额外”努力。

请注意,container_typestd::vector&lt;int&gt; 而不是您要求的 tempalte &lt;typename T&gt; std::vector&lt;T&gt;。如果需要,您需要编写一个小助手。

【讨论】:

  • 谢谢,这确实非常优雅,正是我想要的。不过,您是否也知道一种与模板函数/变量/别名一起使用的方法?
  • @Reizo 使它们成为类模板的静态方法/成员/别名