⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 item_058.htm

📁 C++程序编写规范,适合C++中级读者
💻 HTM
📖 第 1 页 / 共 2 页
字号:
class=GramE>struct</span></span> X {};</span></p>

<p class=MsoNormal style='margin-left:36.0pt'><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal style='margin-left:36.0pt'><span lang=EN-US><span
style='mso-spacerun:yes'>&nbsp; </span><span
style='mso-spacerun:yes'>&nbsp;&nbsp;</span><span class=GramE>template&lt;</span><span
class=SpellE>typename</span> T&gt;</span></p>

<p class=MsoNormal style='margin-left:36.0pt'><span lang=EN-US><span
style='mso-spacerun:yes'>&nbsp; </span><span
style='mso-spacerun:yes'>&nbsp;&nbsp;</span><span class=SpellE><span
class=GramE>int</span></span>* operator+( T , unsigned ) {<i style='mso-bidi-font-style:
normal'>/* do something */</i>}</span></p>

<p class=MsoNormal style='margin-left:36.0pt'><span lang=EN-US>}</span></p>

<p class=MsoNormal style='margin-left:36.0pt'><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal style='margin-left:36.0pt'><span class=SpellE><span
class=GramE><span lang=EN-US>int</span></span></span><span lang=EN-US> main() {</span></p>

<p class=MsoNormal style='margin-left:36.0pt'><span lang=EN-US><span
style='mso-spacerun:yes'>&nbsp; </span><span
style='mso-spacerun:yes'>&nbsp;&nbsp;</span><span class=SpellE>std::vector</span>&lt;N::X&gt;
<span class=GramE>v(</span>5);</span></p>

<p class=MsoNormal style='margin-left:36.0pt'><span lang=EN-US><span
style='mso-spacerun:yes'>&nbsp; </span><span
style='mso-spacerun:yes'>&nbsp;&nbsp;</span><span class=GramE>v[</span>0] ;</span></p>

<p class=MsoNormal style='margin-left:36.0pt'><span lang=EN-US>}</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>语句</span><span lang=EN-US>v[0];</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>在某些标准库的实现上可以编译通过,但是在其它的实现上却不行。这里长话短说(深呼吸一口):这个极端隐晦的问题是因为在大多数</span><span
lang=EN-US>vector&lt;T&gt;::operator[]</span><span style='font-family:宋体;
mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>的实现中都隐藏着像</span><span
class=SpellE><span lang=EN-US>v.begin</span></span><span lang=EN-US>() + n</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>之类的代码,对该</span><span lang=EN-US>operator+</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>函数的名字查找可能会找到用来实例化</span><span lang=EN-US>vector</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>的类型(在这里是</span><span lang=EN-US>X</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>)的名字空间中(在这里是</span><span lang=EN-US>N</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>)。编译器是否会找到像</span><span lang=EN-US>N</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>之类的名字空间中取决于</span><span lang=EN-US>vector&lt;T&gt;::<span
class=SpellE>iterator</span></span><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>是如何定义的,这和标准库的实现有关,也和标准库的实现的版本有关。但是如果编译器真的找到了</span><span
lang=EN-US>N</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>,那么它就会发现</span><span class=SpellE><span
lang=EN-US>N::operator</span></span><span lang=EN-US>+</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>。最终,取决于牵涉到的类型,编译器可能会发现</span><span class=SpellE><span
lang=EN-US>N::operator</span></span><span lang=EN-US>+</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>比起标准库的实现为</span><span lang=EN-US>vector&lt;T&gt;::<span
class=SpellE>iterator</span></span><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>提供的</span><span
class=SpellE><span lang=EN-US>std::operator</span></span><span lang=EN-US>+</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>(也是希望被调用的)匹配得更好。(标准库的实现可以用来避免此问题的一个办法就是不要那样编写</span><span
class=SpellE><span lang=EN-US>v.begin</span></span><span lang=EN-US>() + n</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>之类的代码,这会在无意中加入一个可定制的点:要么使</span><span class=SpellE><span
lang=EN-US>v.begin</span></span><span lang=EN-US>()</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>的类型完全不依赖于模板参数,要么在调用</span><span lang=EN-US>operator+</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>时加上限定符。参见第</span><span lang=EN-US>65</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>条)</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span lang=EN-US>In short, you'll almost certainly never
figure out what's going on from the error message if you're lucky enough to get
an error message, that is, because you might happen to hit the worst of all
possible worlds where <span class=SpellE>N::operator</span>+ is chosen but
unfortunately turns out to be <span class=SpellE>compilable</span>, although
completely unintended and wildly wrong.</span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>简而言之,如果你非常幸运地得到一条错误信息的话,那么你几乎无法根据错误消息来估计到底发生了什么,换句话说,因为你可能碰巧遇到最糟糕的情况:这种情况下编译器选择了</span><span
class=SpellE><span lang=EN-US>N::operator</span></span><span lang=EN-US>+</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>,而且不幸的是能够编译通过,虽然完全是无意的,但却是难以想象的错误。</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span lang=EN-US>If you think you haven't been bit by this,
just think back: Can you remember a time when you wrote code that used the
standard library (for example) and got mysterious and incomprehensible compiler
errors? And you kept slightly rearranging your code and recompiling, and
rearranging some more and compiling some more, until the mysterious compile
errors went away, and then you happily continued on - with at best a faint
nagging curiosity about why the compiler didn't like the only-ever-so-slightly
different arrangement of the code you wrote at first? We've all had those days,
and the odds are decent that the mystery culprit was some form of the
aforementioned problem, where ADL pulled in names from other namespaces
inappropriately just because types from those namespaces were being used
nearby.</span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>如果你认为自己从来没有这个问题咬过,那么回想一下:能否想起某一次编写一些使用了标准库(比如)的代码,却遇到了奇怪的,难以理解的编译错误?你把代码稍做改动然后重新编译,做更多的改动再重新编译,直到奇怪的编译错误不见了,于是你很高兴地继续——最多一边唠叨一边好奇为什么编译器不喜欢你一开始写的只有那么一点不一样的代码?我们都有过这样的时候,那些奇怪的编译错误也是符合</span><span
lang=EN-US>C++</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>标准的,而那个神秘的肇事者就是前面提到的问题,</span><span
lang=EN-US>ADL</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>从其它的名字空间中不当地导入了名字,只因为在附近用到了来自那些名字空间中的类型。</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span lang=EN-US>This problem is not unique to uses of the
standard library. It can and does happen in C++ with the use of any type that
is defined in the same namespace as functions - especially <span class=SpellE>templated</span>
functions, and most especially operators - that aren't specifically related to
that type. Don't do that.</span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>这个问题并不仅仅和使用了标准库有关。如果类型和函数被定义在同一个名字空间——尤其是模板函数(</span><span
class=SpellE><span lang=EN-US>templated</span></span><span lang=EN-US> function</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>),又以操作符为最——但它们之间并无明确的关联,那么在那些用到了这样的类型的</span><span
lang=EN-US>C++</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>程序中,它可能也确实会发生。所以不要那样做。</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span lang=EN-US>Bottom line: You shouldn't have to know
this stuff. The easiest way to avoid this whole category of problems is to in
general avoid putting nonmember functions that are not part of the interface of
a type X into the same namespace as X, and especially never ever put <span
class=SpellE>templated</span> functions or operators into the same namespace as
a user-defined type.</span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>关键在于:你并不需要知道这些东西。一般来说,避免此类问题的最简单的方法就是:避免把不属于类型</span><span
lang=EN-US>X</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>的接口的非成员函数放在与</span><span lang=EN-US>X</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>相同的名字空间中,特别是永远不要把模板函数或操作符和用户定义的类型放在同一个名字空间中。</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span lang=EN-US>Note: Yes, the C++ standard library puts
algorithms and other function templates, such as copy and distance, into the
same namespace as lots of types, such as pair and vector. It puts everything
into a single namespace. That's unfortunate, and it causes exactly these kinds
of very subtle problems. We know better now. Learn from the past. Don't do
that.</span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>注意:是的,</span><span lang=EN-US>C++</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>标准库把算法和其它许多函数模板(</span><span lang=EN-US>function template</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>),如</span><span lang=EN-US>copy</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>和</span><span lang=EN-US>distance</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>,和许多类型,如</span><span lang=EN-US>pair</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>和</span><span lang=EN-US>vector</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>,放在了同一个名字空间中。它把所有东西放在了一个名字空间中。这真是不幸,它导致了前述的那些非常隐晦的问题。我们现在知道的更清楚了,我们应该学习过去的教训。所以不要那样做。</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>关于此问题的另一面,请参见第</span><span lang=EN-US>57</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>条。</span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

</div>

</body>

</html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -