我可以在前向声明中默认模板参数吗

Am I Allowed to Default a Template Argument in a Forward Declaration

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

在ptree.hpp中basic_ptree实际定义为:

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

在 ptree_fwd.hpp 中有一个看起来像 basic_ptree 的前向声明但是有一个新的模板参数 default:

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 中的前向声明,对吧?所以我可以在前向声明中默认模板参数?

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

17.1/14

The set of default template-arguments available for use is obtained by merging the default arguments from all prior declarations of the template in the same way default function arguments are (dcl.fct.default).

[ Example:

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

is equivalent to

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

— end example ]

17.1/16

A template-parameter shall not be given default arguments by two different declarations in the same scope. [ Example:

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

— end example ]

(注意,这些是从最新的草案中摘录的,但据我所知,这些规则近年来没有改变)

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

I feel like this gets really nasty really quick. What if I include 2 separate headers that include different defaults in their forward declarations? Or is that what you're addressing?

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

我个人的意见是在 header 中只有一个声明指定默认模板参数,然后在需要声明的地方包含 header(以及定义).