20

是否可以在不指定或不知道这些参数的情况下转发声明使用默认参数的类?

例如,我想boost::ptr_list< TYPE >在 Traits 类中声明 a 而无需将整个 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*>在我的特征类中指定?(如果我使用后者,我想我还必须转发 declareboost::heap_clone_allocator和 include <memory>。)

我浏览了 Stroustrup 的书 SO,以及互联网的其他内容,但没有找到解决方案。通常人们担心不包含 STL,解决方案是“只包含 STL 头”。但是,Boost 是一个更庞大且编译器密集型的库,因此除非绝对必须,否则我宁愿将其省略。

4

4 回答 4

16

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

即使这是合法的:

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 中给出了一个类似的例子。根据该段,函数默认参数的行为类似。

祝你好运,让前向声明能够表现自己,而不是对所有事情都吐槽!

于 2010-04-28T05:55:47.443 回答
9

我认为您不能使用默认参数转发声明模板,除非相关库提供了自己的转发声明头。这是因为您无法重新指定默认参数(即使它们匹配... 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 以删除默认参数,因此无法扩展到第 3 方库。也许我们应该游说 C++0x 团队允许对默认模板参数进行等效的重新指定,比如 typedefs...?

于 2010-02-22T03:24:31.787 回答
2

任何使用前向声明 boost 内容的工具的编译单元都需要包含 boost 标头,除非您有某些程序实际上不会使用工具的 boost 部分。

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

请记住,在未来的 Boost 版本中可能会添加更多默认模板参数。我建议不要这条路线。如果您的目标是加快编译时间,我会考虑使用 a#define来指示是否应该禁用使用该 boost 库的代码。这样你就避免了前向声明的麻烦。

于 2009-11-24T19:34:30.913 回答
0

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

如果我的一个标题使用例如。std::vector 那么我必须包含整个标题。从这个时候开始,每次我都包含我的标题,即使我的源代码根本没有引用 std::vector 标题也会与我的标题一起包含在内。如果您在很多地方包含此标头,这将意味着大量过度解析。

所以我转发声明了 std::vector 并使用了 std::vector* ,但由于默认参数,我的代码不想编译。如果我将默认参数放在我的头文件中,那么由于默认参数尊重,编译器会拒绝编译 stl 头文件。

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

于 2010-04-28T05:47:58.287 回答