声明会影响std名称空间吗? [英] Can a declaration affect the std namespace?

查看:144
本文介绍了声明会影响std名称空间吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

#include <iostream>
#include <cmath>

/* Intentionally incorrect abs() which seems to override std::abs() */
int abs(int a) {
    return a > 0? -a : a;
}

int main() {
    int a = abs(-5);
    int b = std::abs(-5);
    std::cout<< a << std::endl << b << std::endl;
    return 0;
}

我希望输出是-55,但是输出是-5-5.

I expected that the output will be -5and 5, but the output is the -5 and -5.

我不知道为什么会发生这种情况?

I wonder why this case will happen?

std的使用有什么关系吗?

Does it have anything to do with the use of std or what?

推荐答案

语言规范允许实现,以通过声明(并定义) global 命名空间中的标准函数,然后通过using-declaration将它们引入命名空间std中来实现<cmath>.尚不确定是否使用这种方法

The language specification allows implementations to implement <cmath> by declaring (and defining) the standard functions in global namespace and then bringing them into namespace std by means of using-declarations. It is unspecified whether this approach is used

20.5.1.2标头
4 [...]但是,在C ++标准库中,声明(除了在C中定义为宏的名称)位于名称空间std的名称空间范围(6.3.6)之内. .尚不确定这些名称(包括任何重载)是否存在. 首先在全局名称空间范围内声明在第21至33条和附件D中添加的内容,然后通过显式using-声明(10.3.3)将其注入名称空间std.

20.5.1.2 Headers
4 [...] In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (6.3.6) of the namespace std. It is unspecified whether these names (including any overloads added in Clauses 21 through 33 and Annex D) are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (10.3.3).

显然,您正在处理一种决定采用这种方法的实现方式(例如GCC). IE.您的实现提供了::abs,而std::abs只是引用"了::abs.

Apparently, you are dealing with one of implementations that decided to follow this approach (e.g. GCC). I.e. your implementation provides ::abs, while std::abs simply "refers" to ::abs.

在这种情况下仍然存在的一个问题是,为什么除了标准的::abs之外,您还可以声明自己的::abs,即为什么没有多重定义错误.这可能是由某些实现(例如GCC)提供的另一个功能引起的:它们将标准函数声明为所谓的弱符号,因此允许您用自己的定义替换"它们.

One question that remains in this case is why in addition to the standard ::abs you were able to declare your own ::abs, i.e. why there's no multiple definition error. This might be caused by another feature provided by some implementations (e.g. GCC): they declare standard functions as so called weak symbols, thus allowing you to "replace" them with your own definitions.

这两个因素共同产生了您观察到的效果:::abs的弱符号替换也导致了std::abs的替换.这与语言标准的吻合程度是个不同的故事……无论如何,请不要依赖这种行为-语言无法保证.

These two factors together create the effect you observe: weak-symbol replacement of ::abs also results in replacement of std::abs. How well this agrees with the language standard is a different story... In any case, don't rely on this behavior - it is not guaranteed by the language.

在GCC中,此行为可以通过以下简约示例来重现.一个源文件

In GCC this behavior can be reproduced by the following minimalistic example. One source file

#include <iostream>

void foo() __attribute__((weak));
void foo() { std::cout << "Hello!" << std::endl; }

另一个源文件

#include <iostream>

void foo();
namespace N { using ::foo; }

void foo() { std::cout << "Goodbye!" << std::endl; }

int main()
{
  foo();
  N::foo();
}

在这种情况下,您还将观察到第二个源文件中::foo("Goodbye!")的新定义也会影响N::foo的行为.这两个调用都将输出"Goodbye!".并且,如果您从第二个源文件中删除::foo的定义,则这两个调用将分派到::foo的原始"定义并输出"Hello!".

In this case you will also observe that the new definition of ::foo ("Goodbye!") in the second source file also affects the behavior of N::foo. Both calls will output "Goodbye!". And if you remove the definition of ::foo from the second source file, both calls will dispatch to the "original" definition of ::foo and output "Hello!".

上面20.5.1.2/4给出的许可可以简化<cmath>的实现.允许实现仅包含C样式的<math.h>,然后在std中重新声明功能,并添加一些特定于C ++的添加和调整.如果上面的解释正确地描述了问题的内部机制,那么它的主要部分取决于功能的 C样式版本的弱符号的可替换性.

The permission given by the above 20.5.1.2/4 is there to simplify implementation of <cmath>. Implementations are allowed to simply include C-style <math.h>, then redeclare the functions in std and add some C++-specific additions and tweaks. If the above explanation properly describes the inner mechanics of the issue, then a major part of it depends on replaceability of weak symbols for C-style versions of the functions.

请注意,如果在上述程序中仅将int全局替换为double,则代码(在GCC下)将表现为预期"-将输出-5 5.发生这种情况是因为C标准库没有abs(double)函数.通过声明我们自己的abs(double),我们不会替换任何内容.

Note that if we simply globally replace int with double in the above program, the code (under GCC) will behave "as expected" - it will output -5 5. This happens because C standard library does not have abs(double) function. By declaring our own abs(double), we do not replace anything.

但是,如果从int切换为double之后,我们也从abs切换到fabs,原始的怪异行为将再次显示出来(输出-5 -5).

But if after switching from int with double we also switch from abs to fabs, the original weird behavior will reappear in its full glory (output -5 -5).

这与上面的解释一致.

这篇关于声明会影响std名称空间吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆