C++ 带有转发声明的默认模板参数

C++ 带有转发声明的默认模板参数,c++,templates,forward-declaration,C++,Templates,Forward Declaration,是否可以向前声明一个使用默认参数的类,而不指定或不知道这些参数 例如,我想在Traits类中声明一个boost::ptr_list,而不必将整个boost库拖到包含Traits的每个文件中。我想申报 namespace boost{template class ptr_list},但这不起作用,因为它与真正的类声明不完全匹配: template < class T, class CloneAllocator = heap_clone_allocator, class All

是否可以向前声明一个使用默认参数的类,而不指定或不知道这些参数

例如,我想在Traits类中声明一个
boost::ptr_list
,而不必将整个boost库拖到包含Traits的每个文件中。我想申报
namespace boost{template class ptr_list}
,但这不起作用,因为它与真正的类声明不完全匹配:

template < class T,
    class CloneAllocator = heap_clone_allocator,
    class Allocator = std::allocator<void*>
    >
class ptr_list { ... };
模板
类ptr_列表{…};
我的选项是否仅限于使用它,或者在我的traits类中指定
boost::ptr\u list
?(如果使用后者,我还必须向前声明
boost::heap\u clone\u分配器
,并包括
。)


我浏览了斯特劳斯特普的书,所以,和互联网的其他部分,还没有找到解决办法。通常人们关心的是不包含STL,解决方案是“只包含STL头”。然而,Boost是一个更庞大、编译器密集的库,因此,除非我必须这样做,否则我更愿意省略它。

任何使用你的工具的编译单元,不管怎样,都需要包含boost头,除非你有某些程序实际上不使用你工具的boost部分

确实,通过向前声明,可以避免包含此类程序的boost头。但是对于那些实际使用boost部分的程序,您必须手动包含boost头文件(或者有一个
#ifdef


请记住,在未来的Boost版本中可以添加更多的默认模板参数。我建议不要走这条路线。如果您的目标是加快编译时间,我会考虑使用<代码>定义> <代码>来指示是否禁用禁用使用该升压库的代码。这样可以避免转发声明的麻烦。

我不认为可以使用默认参数转发声明模板,除非相关库提供了自己的转发声明头。这是因为您无法重新指定默认参数(即使它们匹配…gcc仍将报告“错误:重新定义默认参数”)

因此,据我所知,解决方案是让库提供一个转发声明头Foo_fwd.h:

#ifndef INCLUDED_Foo_fwd_h_
#define INCLUDED_Foo_fwd_h_
template<class T, class U=char> class Foo; // default U=char up here
#endif
#如果包含NDEF(u Foo)fwd(h)_
#定义包含的\u Foo\u fwd\u h_
模板类Foo;//这里的默认U=char
#恩迪夫
那么Foo.h中的完整实现将是:

#ifndef INCLUDED_Foo_h_
#define INCLUDED_Foo_h_
#include "Foo_fwd.h"
template<class T, class U> class Foo { /*...*/ }; // note no U=char here
#endif
#如果包含ndef(u Foo)_
#定义包含的\u Foo\u h_
#包括“Foo_fwd.h”
模板类Foo{/*…*/};//注意这里没有U=char
#恩迪夫

所以现在您的代码也可以使用Foo_fwd.h。。。但不幸的是,由于这种方法需要修改原始Foo.h以删除默认参数,因此无法扩展到第三方库。也许我们应该游说C++0x团队允许对默认模板参数进行等效的重新指定,就像typedefs…?

这里也有同样的问题。但是使用STL

如果我的一个头使用例如std::vector,那么我必须包含整个头。从这个时候起,每次我包括我的头,即使我的源代码根本没有引用std::vector,头也会随我的头一起包括。如果你把这个标题放在很多地方,那就意味着有很多越界

因此,我向前声明了std::vector并使用了std::vector*,但由于默认参数,我的代码不想编译。如果我将默认参数放在头中,那么编译器会由于默认参数而拒绝编译stl头


在这种情况下,我要做的是创建我自己的Vector类,该类修改std::Vector并将每个方法调用转发给它。也许这可以解决问题。

是的。可以在任何时间、任何地点指定默认模板参数,只要声明彼此不冲突。它们最终从各种声明中合并在一起

即使这是合法的:

template< class A, class B, class C = long >
class X;

template< class A, class B = int, class C >
class X;

template< class A = short, class B, class C >
class X { };
模板
X类;
模板
X类;
模板
类X{};
§14.1/10中给出了一个类似的例子。根据该段,函数默认参数的行为类似


祝你好运,让你的未来宣言言行一致,而不是什么都吐出来

Boost是一组基本上只有标题的库。为什么不只使用您需要的组件(及其依赖项)?并不是说没有涉及到一些工作,但这是我们通常要做的。我需要——ptr_列表是我唯一需要的文件。唯一的问题是,一个单一的增压收割台包括一系列其他收割台。MakeDependen的一个简单应用程序显示,just ptr_list至少包含385个文件:boost的配置、详细信息、迭代器、mpl、预处理器、范围、智能ptr、类型特征和实用程序——以命名主要模块。你肯定能理解我是如何避免在不必要的时候包含这些内容的。难怪编译时间一飞冲天。是的,包含这么多文件可能会很烦人。但我认为正确的问题是:有没有办法找出为什么包含这些文件?可以将这些包含的文件进行划分,以便只包含必要的内容。这似乎不是一个简单的解决方法。由于类声明是一个不可分割的组件,如果类的任何函数在报头中使用某个模糊的mpl特性,则使用该类的所有代码都必须包含该mpl报头。这是令人悲哀的。假设您主要关心的是减少编译时间,那么ccache可能会很有用