为什么<cmath>中的某些函数不在std命名空间中?</cmath>

时间:2012-06-18 15:21:54

标签: c++ namespaces cmath

我正在开发一个适用于多种算术类型的项目。所以我制作了一个标题,其中定义了用户定义的算术类型的最低要求:

user_defined_arithmetic.h:

typedef double ArithmeticF;   // The user chooses what type he 
                              // wants to use to represent a real number

namespace arithmetic          // and defines the functions related to that type
{

const ArithmeticF sin(const ArithmeticF& x);
const ArithmeticF cos(const ArithmeticF& x);
const ArithmeticF tan(const ArithmeticF& x);
...
}

令我不安的是,当我使用这样的代码时:

#include "user_defined_arithmetic.h"

void some_function()
{
    using namespace arithmetic;
    ArithmeticF lala(3);
    sin(lala);
}

我收到编译错误:

error: call of overloaded 'sin(ArithmeticF&)' is ambiguous
candidates are:
double sin(double)
const ArithmeticF arithmetic::sin(const ArithmeticF&)

我从未使用<math.h>标头,只使用<cmath>。我从未在头文件中使用using namespace std

我正在使用gcc 4.6。*。我检查了含有模糊声明的标题是什么,结果是:

mathcalls.h:

Prototype declarations for math functions; helper file for <math.h>.
...

我知道,<cmath>包含<math.h>,但它应该屏蔽std命名空间的声明。我深入研究<cmath>标题并找到:

cmath.h:

...

#include <math.h>

...

// Get rid of those macros defined in <math.h> in lieu of real functions.
#undef abs
#undef div
#undef acos
...

namespace std _GLIBCXX_VISIBILITY(default)
{
...

因此命名空间std在<{strong> #include <math.h>之后开始。这里有什么问题,或者我误解了什么?

3 个答案:

答案 0 :(得分:19)

允许C ++标准库的实现在全局命名空间和std中声明C库函数。有人会称这是一个错误,因为(正如你所发现的)命名空间污染可能会导致与你自己的名字发生冲突。但是,就是这样,所以我们必须忍受它。您只需将您的姓名限定为arithmetic::sin

用标准(C ++ 11 17.6.1.2/4)的话来说:

  

然而,在C ++标准库中,声明(除了   在C)中定义为宏的名称在命名空间std的命名空间范围(3.3.6)内。 是的   未指定是否首先在全局命名空间范围内声明这些名称然后注入   通过显式使用声明(7.3.3)进入命名空间std。

答案 1 :(得分:3)

如果你真的想要,你总是可以在cmath周围写一个小包装,沿着以下几行:

//stdmath.cpp
#include <cmath>
namespace stdmath
{
    double sin(double x)
    {
        return std::sin(x);
    }
}

//stdmath.hpp
#ifndef STDMATH_HPP
#define STDMATH_HPP
namespace stdmath {
    double sin(double);
}
#endif

//uses_stdmath.cpp
#include <iostream>
#include "stdmath.hpp"

double sin(double x)
{
    return 1.0;
}

int main()
{
    std::cout << stdmath::sin(1) << std::endl;
    std::cout << sin(1) << std::endl;
}

我认为附加函数调用可能会有一些开销,具体取决于编译器的聪明程度。

答案 2 :(得分:1)

这只是一个开始解决这个问题的拙劣尝试。 (欢迎提出建议。)

我一直在处理这个问题。一个案例是这个案例非常明显的问题:

#include<cmath>
#include<iostream>

namespace mylib{
    std::string exp(double x){return "mylib::exp";}
}

int main(){
    std::cout << std::exp(1.) << std::endl; // works
    std::cout << mylib::exp(1.) << std::endl; // works

    using namespace mylib;
    std::cout << exp(1.) << std::endl; //doesn't works!, "ambiguous" call
    return 0;
}

在我看来,这是一个令人讨厌的错误,或者至少是一个非常不幸的情况。 (至少在GCC和clang - 使用GCC库 - 在Linux中。)

最近我又给了它一个问题。通过查看cmath(GCC),似乎标题只是为了重载C函数并在过程中搞砸了命名空间。

namespace std{
   #include<math.h>
}
//instead of #include<cmath>

有了这个工作

using namespace mylib;
std::cout << exp(1.) << std::endl; //now works.

我几乎可以肯定这与#include<cmath>不完全相同,但大多数功能似乎都有效。

最糟糕的是,最终某些依赖库最终会#inclulde<cmath>。为此,我找不到解决方案。

注意:毋庸置疑,这根本不起作用

namespace std{
   #include<cmath> // compile errors
}