¿Por qué algunas funciones en no están en el espacio de nombres estándar?

Estoy desarrollando un proyecto que funciona con múltiples tipos aritméticos. Así que hice un encabezado, donde se definen los requisitos mínimos para un tipo aritmético definido por el usuario:

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); ... } 

Lo que me preocupa es que cuando uso un código como este:

 #include "user_defined_arithmetic.h" void some_function() { using namespace arithmetic; ArithmeticF lala(3); sin(lala); } 

Me sale un error del comstackdor:

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

Nunca he usado el , solo el . Nunca utilicé el using namespace std en un archivo de encabezado.

Estoy usando gcc 4.6. *. Comprobé cuál es el encabezado que contiene la statement ambigua y resulta ser:

mathcalls.h:

 Prototype declarations for math functions; helper file for . ... 

Sé que incluye , pero debe proteger las declaraciones por el espacio de nombres estándar. encabezado y encuentro:

cmath.h:

 ... #include  ... // Get rid of those macros defined in  in lieu of real functions. #undef abs #undef div #undef acos ... namespace std _GLIBCXX_VISIBILITY(default) { ... 

Entonces el espacio de nombres std comienza después de #include . ¿Hay algo mal aquí o malinterpreté algo?

Las implementaciones de la biblioteca estándar de C ++ pueden declarar las funciones de la biblioteca C en el espacio de nombres global así como en el std . Algunos llamarían a esto un error, ya que (como has descubierto) la contaminación del espacio de nombres puede causar conflictos con tus propios nombres. Sin embargo, así son las cosas, así que debemos vivir con eso. Tendrás que calificar tu nombre como arithmetic::sin .

En las palabras del estándar (C ++ 11 17.6.1.2/4):

En la biblioteca estándar de C ++, sin embargo, las declaraciones (a excepción de los nombres que se definen como macros en C) se encuentran dentro del scope del espacio de nombres (3.3.6) del espacio de nombres std . No se especifica si estos nombres se declaran primero dentro del ámbito del espacio de nombres global y luego se inyectan en el espacio de nombres std mediante declaraciones de uso explícitas (7.3.3).

Si realmente quisieras, siempre podrías escribir una pequeña envoltura alrededor de cmath , en la línea de:

 //stdmath.cpp #include  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  #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; } 

Supongo que podría haber algo de sobrecarga de la llamada de función adicional, dependiendo de qué tan inteligente sea el comstackdor.

Este es solo un humilde bash de comenzar a resolver este problema. (Las sugerencias son bienvenidas)

He estado lidiando con este problema por mucho tiempo. Un caso donde el problema es muy obvio es este caso:

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

En mi opinión, esto es un error molesto o al menos una situación muy desafortunada. (Al menos en GCC, y clang --utilizando la biblioteca GCC-- en Linux.)

Últimamente le di otra oportunidad al problema. Al observar el cmath (de GCC) parece que el encabezado está allí simplemente para sobrecargar las funciones C y arruinar el espacio de nombres en el proceso.

 namespace std{ #include } //instead of #include 

Con esto esto funciona

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

Estoy casi seguro de que esto no es exactamente equivalente a #include pero la mayoría de las funciones parecen funcionar.

Lo peor de todo es que eventualmente alguna biblioteca de dependencia eventualmente tendrá #inclulde . Por eso no pude encontrar una solución todavía.

NOTA : No hace falta decir que esto no funciona para nada

 namespace std{ #include // compile errors }