是否可以转发声明一个使用默认参数的类而不指定或知道这些参数?
例如,我想在Traits类中声明boost::ptr_list< TYPE >
,而不将整个Boost库拖到包含特征的每个文件中。我想申报
namespace boost { template<class T> class ptr_list< T >; }
,但这不起作用,因为它与真正的类声明不完全匹配:
template < class T,
class CloneAllocator = heap_clone_allocator,
class Allocator = std::allocator<void*>
>
class ptr_list { ... };
我的选择只是与它一起生活或在我的特质类中指定boost::ptr_list< TYPE, boost::heap_clone_allocator, std::allocator<void*>
吗? (如果我使用后者,我还必须转发声明boost::heap_clone_allocator
并包括<memory>
,我想。)
我查看了Stroustrup的书,SO以及互联网的其他部分并没有找到解决方案。通常人们担心不包括STL,解决方案是“只包括STL标题”。但是,Boost是一个更大规模和编译器密集型的库,因此除非我绝对必须,否则我更愿意将其删除。
答案 0 :(得分:13)
是。可以随时随地指定默认模板参数,只要声明不会相互冲突即可。它们最终从各种声明合并在一起。
即使这是合法的:
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 { };
§14.1/ 10中给出了类似的例子。根据该段,函数默认参数的行为类似。
祝所有前瞻宣言表现得好,而不是对所有事情进行抨击,祝你好运!
答案 1 :(得分:7)
我认为您不能使用默认参数转发声明模板,除非有问题的库提供了自己的前向声明标头。这是因为你不能重新指定默认参数(即使它们匹配...... 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
然后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
所以现在你的代码也可以使用Foo_fwd.h ......但遗憾的是,由于这种方法需要修改原始的Foo.h以删除默认参数,因此不会扩展到第三方库。也许我们应该游说C ++ 0x工作人员以允许等效重新指定默认模板参数,àlatypedef ...?
答案 2 :(得分:3)
任何使用你的设施进行前向声明增强功能的编译单元都需要包含boost头,除非你有某些程序实际上不会使用你设施的增强部分。
通过前向声明,您可以避免包含此类程序的boost标头。但是你必须手动为那些实际使用boost部分的程序包含boost标题(或者有一个#ifdef
)。
请记住,可以在将来的Boost版本中添加更多默认模板参数。我建议反对这条路线。如果您的目标是加快编译时间,我会考虑使用#define
来指示是否应禁用使用该boost库的代码。这样就可以避免前方声明的麻烦。
答案 3 :(得分:0)
同样的问题在这里。但是用STL。
如果我的一个标题使用例如。 std :: vector然后我必须包括整个标题。从这个时候我每次都包含我的标题,即使我的源代码没有引用std :: vector,所有标题都包含在我的标题中。如果你在很多地方都包含这个标题,这将意味着大量的过度分析。
所以我转发声明了std :: vector并使用了std :: vector *,但由于默认参数,我的代码不想编译。如果我将默认参数放在我的头文件中,那么由于默认参数respectification,编译器拒绝编译stl头。
我在这种情况下尝试做的是创建我自己的Vector类,它适应std :: vector并转发每个方法调用。可能这可以解决问题。