C++ std::wstring的转发声明

C++ std::wstring的转发声明,c++,stl,forward-declaration,C++,Stl,Forward Declaration,std::wstring是一个模板实例化,所以您不能只向前声明它。您必须使用头文件。您不能#包括,你(几乎)别无选择 原因是wstring是在命名空间std中定义的,并且类型定义为std::basic_string。更详细地说,std::wstring是std::basic_string。这意味着为了转发declarestd::wstring,您必须转发declarestd::char\u traits和std::basic\u string名称空间内的std。因为(除了少数例外情况外)标准禁止

std::wstring
是一个模板实例化,所以您不能只向前声明它。您必须使用头文件。

您不能<代码>#包括,你(几乎)别无选择

原因是
wstring
是在命名空间
std
中定义的,并且类型定义为
std::basic_string
。更详细地说,
std::wstring
std::basic_string
。这意味着为了转发declare
std::wstring
,您必须转发declare
std::char\u traits
std::basic\u string
名称空间内的
std
。因为(除了少数例外情况外)标准禁止向命名空间
std
(17.4.3.1/1)添加定义或声明,最终您不能以符合标准的方式转发声明任何标准模板或类型。具体来说,这意味着您不能向前声明
std::wstring

是的,我们都同意有一个
标题会很方便,比如
。但是没有<代码>也不像
那样是编译的核心,但无论如何。你有两个选择:
#包括
或使用。

我不认为避免#包括会给你带来任何真正的好处,但你可以这样做:

// This is a header file.

class MyClass; // It can be forward declared because the function uses reference.
// However, how can I do forward declaraion about std::wstring?
// class std::wstring; doesn't work.
VOID Boo(const MyClass& c);
VOID Foo(const std::wstring& s);

您不能在一致性实现中转发声明
std::wstring
,这不是因为它是
模板
专门化的
typedef
,也不是因为它有未知数量的模板参数(不是;这些参数是严格指定的)但是,因为一致性程序有一个约束,禁止它们向
std
命名空间添加任何声明或定义,而不是在用户定义类型上专门化的标准模板的显式专门化


17.4.3.1[lib.reserved.names]/1中说明了此约束。对于
std::wstring
的转发声明也不例外,您必须
#包括
,以使声明
std::wstring
以一致的方式可用不编译。但这确实:

In file included from /usr/include/c++/4.4/string:41,
                 from example.cpp:15:
/usr/include/c++/4.4/bits/stringfwd.h:52: error: redefinition of default argument for ‘class _Traits’
example.cpp:8: note: original definition appeared here

但是,此声明与
头文件不兼容,如果在其后面包含
,则应查看该头文件。所以它真的不安全。

因为如果它可以向前声明,它会比导入头文件好。@Fred Nurk:大概是因为它会编译得更快。@TonyK:我期待着:但是将构建时间从253秒降低到252.8秒不值得追求。我希望本杰明有一个我想不出的更好的理由。@Fred:如果可以的话,我不想包含不必要的头文件。标题(有问题)只处理引用。所以它需要知道类名。如果我包含MyClass.h和字符串,它将使依赖关系成为其他模块。@FredNurk Benjamin似乎认为这永远不会改变。谁能确定,无论C++中有多少种前向语言修订,文件中的单个字符都不会改变。C++2099?这很难预测?在需要额外的标题信息之前,引入额外的标题信息从来都不是一件好事。(可能需要C++标准,但不好)。不允许实现将默认模板参数添加到Basic字符串中。但我同意,包括在内很容易,没有真正的缺点。@Fred:为什么不呢?该标准规定了必须编译的代码,并没有禁止供应商扩展。只要默认值保持
basic_string
与标准中的操作完全相同,编译器供应商就可以自由添加他们想要的任何额外模板参数。Argh。我找不到引用,但由于某种原因,我记得读到标准模板类可以有额外的默认参数。@比利:当基本字符串作为模板参数传递时(
template void f();…f()
),如果基本字符串有额外的模板参数,则一致性代码将中断。因此,实现不能添加模板参数,而且仍然是严格一致的。这也是模板参数不是很有用的一个原因,但在C++0x中使用“模板typedefs”对它有很大帮助。@Wilhelmtell,我肯定读过一些相同的东西,但我不记得在哪里了。无论它在哪里,它都是错误的:我总是将其解释为添加一个新名称,比如std::CharlesBailey,而不是声明一个“存在”的名称。(也许更清楚地说,“Add”是一个重要的词,而不是说“对于一个C++程序,在名字空间STD中声明或定义它是不确定的”。但是我不能说你的解释是完全错误的。然而,至少在一个没有添加模板参数的实现中(这肯定不是严格符合要求的),它应该是可移植的(并且符合性值得怀疑),就像我在回答中所做的那样。@FredNurk:如果每个人都以同样的方式解释事情,这个世界将是一个乏味(如果简单的话)的地方!我已经检查过了,没有看到任何东西。看起来是最相关的,但由于此声明不需要显式实例化(这是一个定义),我看不出它是否适用。这确实是不兼容的,但这仅仅意味着您不需要这样做。这并不是说正确操作的“安全性”。如果出于某种原因,
#include
在一个简单的头文件中有800行我不需要的代码(或者由于bug跟踪而不需要的代码),那么就应该向前声明。如果头是可移植DLL中可用的方法,而调用的EXE不知道或不关心
std::string
在实现方面是什么(因为DLL完成了所有工作),该怎么办?使用
void*
或一个以前没有人见过的不透明指针,强类型环境就不会产生这种效果。为什么嘘
namespace std {
  template<class Char>
  struct char_traits;

  template<class T>
  struct allocator;

  template<class Char, class Traits=char_traits<Char>,
           class Allocator=allocator<Char> >
  struct basic_string;

  typedef basic_string<wchar_t> wstring;
}

#include <string>
In file included from /usr/include/c++/4.4/string:41,
                 from example.cpp:15:
/usr/include/c++/4.4/bits/stringfwd.h:52: error: redefinition of default argument for ‘class _Traits’
example.cpp:8: note: original definition appeared here
namespace std{
class wstring;
}