C++ 声明是否会影响std命名空间? #包括 #包括 /*故意不正确的abs(),它似乎覆盖了std::abs()*/ 内部abs(内部a){ 返回a>0?-a:a; } int main(){ INTA=绝对值(-5); INTB=std::abs(-5); std::cout

C++ 声明是否会影响std命名空间? #包括 #包括 /*故意不正确的abs(),它似乎覆盖了std::abs()*/ 内部abs(内部a){ 返回a>0?-a:a; } int main(){ INTA=绝对值(-5); INTB=std::abs(-5); std::cout,c++,std,reserved,C++,Std,Reserved,通过声明(和定义)全局名称空间中的标准函数,然后通过使用声明将它们引入名称空间std来实现的语言规范实现。是否使用此方法尚不明确 20.5.1.2标题 在C++标准库中, 4 ……,但是声明(除了在C中定义为宏的名称)在命名空间 STD< /COD>的命名空间范围(6·3.6)内。未指定这些名称是否包括任何重载。 在第21条至第33条和附录D中添加的)首先在全局命名空间范围内声明,然后通过显式使用声明(10.3.3)将其注入命名空间std 显然,您正在处理一个决定采用这种方法的实现(例如GCC)

通过声明(和定义)全局名称空间中的标准函数,然后通过使用声明将它们引入名称空间
std
来实现
的语言规范实现。是否使用此方法尚不明确

20.5.1.2标题
在C++标准库中,<强> 4 ……,但是声明(除了在C中定义为宏的名称)在命名空间<代码> STD< /COD>的命名空间范围(6·3.6)内。未指定这些名称是否包括任何重载。 在第21条至第33条和附录D中添加的)首先在全局命名空间范围内声明,然后通过显式使用声明(10.3.3)将其注入命名空间
std

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

本例中剩下的一个问题是,除了标准的
::abs
之外,为什么您能够声明自己的
::abs
,即为什么没有多个定义错误。这可能是由某些实现(例如GCC)提供的另一个功能造成的:它们将标准函数声明为弱符号,从而允许您用自己的定义“替换”它们

这两个因素共同产生了你观察到的效果:弱符号替换
::abs
也会导致替换
std::abs
。这与语言标准的一致程度是不同的……无论如何,不要依赖于这种行为——语言无法保证这一点

在GCC中,这种行为可以通过下面的简单示例重现

#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;
}
#include <iostream>

void foo() __attribute__((weak));
void foo() { std::cout << "Hello!" << std::endl; }
#包括
void foo()_属性__((弱));

void foo(){std::cout您的代码会导致未定义的行为

C++17[外部名称]/4:


使用外部链接声明的C标准库中的每个函数签名都保留给实现,以用作具有外部“C”和外部“C++”链接的函数签名,或用作全局命名空间中命名空间作用域的名称

因此,您不能使用与标准C库函数相同的原型创建函数
intabs(int);
。无论您实际包含哪些头,或者这些头是否也将C库名称放入全局命名空间


但是,如果您提供不同的参数类型,则允许重载
abs

您对
abs
的实现是不正确的。@RichardCriten这就是问题所在。OP询问为什么添加此损坏的
abs
会影响
std::abs()
。有趣的是,我用叮当声得到了
5
5
,用gcc得到了
-5
-5
。Cmake不是一个编译器,而是一个构建系统。你可以使用Cmake与各种编译器一起构建。我可能会建议你只需使用函数
返回0
,这样就不会让人们认为你是一个编译器9常规地错误地实现了该函数,并使期望的和实际的行为更加清晰。正如我在cmath的源代码中所看到的,对于
using::abs;
而言,与
using::asin;
类似,因此您可以覆盖声明,另一点需要提及的是,std命名空间函数中定义的不是为int声明的,而是为int声明的从标准的角度来看,行为是未定义的。但是当我删除代码中的
#include
时,我得到了相同的答案。`@Peter但是你从哪里得到std::abs?--它可能是通过另一个include包含的,这时你回到了这个解释。(对于编译器来说,头是否直接或间接包含并不重要。)@Peter:
abs
也可以在
中声明,这可能通过
隐式包含。请尝试删除自己的
abs
并查看它是否仍在编译。“或者作为全局命名空间中命名空间作用域的名称”,因此不能在全局命名空间中重载。@xskxzr我不确定您引用的文本的解释;如果这意味着用户不能在全局命名空间中声明该名称的任何内容,那么我引用的文本的前一部分将是多余的,就像大多数[extern.names]一样/3.这让我觉得这里还有别的打算。
#include <iostream>

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

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

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