【问题标题】:Am I Allowed to Default a Template Argument in a Forward Declaration我是否允许在前向声明中默认模板参数
【发布时间】:2023-10-21 02:41:02
【问题描述】:

所以我试图了解 Boost 的 ptree 实现发生了什么。

在ptree.hpp中basic_ptree实际上是定义的:

template<class Key, class Data, class KeyCompare>
class basic_ptree

在 ptree_fwd.hpp 中有一个看起来像 basic_ptree 的前向声明,但带有一个新的模板参数默认值:

template < class Key, class Data, class KeyCompare = std::less<Key> >
class basic_ptree;

最后在 ptree_fwd.hpp ptreetypedef'd:

typedef basic_ptree<std::string, std::string> ptree;

这是 ptree_fwd.hpp 中的前向声明,对吗?所以我可以在前向声明中默认模板参数吗?

【问题讨论】:

  • 您可以在模板声明中为模板参数声明默认值,就像在函数声明中为函数参数声明默认值一样。
  • @SamVarshavchik 是的,知道这一点。我可以在前向声明中默认模板参数吗?
  • 这就是我写的。
  • @JonathanMee 声明(可能多次)和定义都可以,最后合并;与函数参数相同。
  • @JonathanMee 我正在写一个答案,一会儿就会清楚:)

标签: c++ templates metaprogramming forward-declaration default-arguments


【解决方案1】:

是的,你可以。但是每个默认模板参数只能指定一次。

17.1/14

可用的默认模板参数集是通过以与默认函数参数相同的方式合并模板的所有先前声明的默认参数获得的 (dcl.fct.default)。

[ 示例:

template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;

等价于

template<class T1 = int, class T2 = int> class A;

— 结束示例 ]

还有17.1/16

一个模板参数不应被同一范围内的两个不同声明赋予默认参数。 [ 示例:

template<class T = int> class X;
template<class T = int> class X { /* ... */ };  // error

— 结束示例 ]

注意,这些来自最新的草案,但据我所知,这些规则近年来没有改变

如果您希望能够在只知道声明的情况下使用默认参数,则必须在声明中定义它们。以上也回答了您在 cmets 中提出的问题:

我觉得这很快就会变得非常讨厌。如果我在其前向声明中包含 2 个包含不同默认值的单独标头怎么办?或者这就是您要解决的问题?

如果你这样做了,你的程序将是错误的,因为你只能指定每个默认参数一次。有两个声明,一个定义默认参数,另一个不定义,并不会真正引起任何问题,因为它们彼此之间没有分歧。这仅意味着如果只知道没有默认值的版本,则在实例化模板时必须指定 all 参数。

我个人的意见是,在标头中只包含一个声明来指定默认模板参数,然后在需要声明的任何地方包含该标头(以及定义)。

【讨论】:

  • 所以就我自己的前向声明而言,我显然不能再前向声明一个默认值。但是它不匹配:(我是否必须在我默认在那里的typedef中做那个讨厌的事情,因为实际上我的代码的ptree用法默认为我的typedef而不是使用那个在 ptree_fwd.hpp 中定义,如果 Boost 要改变任何东西,它显然会产生非常负面的影响。
  • 所以我的问题最初实际上是 2 个问题合并为 1 个问题。我已经简化了这个问题,使其成为一个更完整的答案。但我也将问题的另一半分成了一个单独的问题。如果你觉得如此倾向,我也会在这里欣赏一些方向:*.com/q/48302501/2642059