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


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 código como este:{[13]]}

#include "user_defined_arithmetic.h"

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

Recibo un error del compilador:

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

Nunca he usado el encabezado <math.h>, solo el <cmath>. Nunca he usado el using namespace std en un archivo de cabecera.

Estoy usando gcc 4.6.*. He comprobado cuál es el encabezado que contiene la declaración ambigua y resulta ser:

Mathcalls.h:

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

Sé que <cmath> incluye <math.h>, pero debería proteger las declaraciones por el espacio de nombres std. Indago en el encabezado <cmath> y encuentro:

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)
{
...

Así que el espacio de nombres std comienza después de el #include <math.h>. ¿Hay algo mal aquí, o he malinterpretado algo?

Author: Martin Drozdik, 2012-06-18

3 answers

Las implementaciones de la biblioteca estándar de C++ están permitidas para declarar las funciones de la biblioteca de C en el espacio de nombres global, así como en std. Algunos llamarían a esto un error, ya que (como has encontrado) 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 ello. Solo 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, la declaraciones (excepto los nombres que se definen como macros en C) están dentro del ámbito de espacio de nombres (3.3.6) del espacio de nombres std. es no especificado 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 el uso explícito de-declarations (7.3.3).

 16
Author: Mike Seymour,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-18 15:32:56

Si realmente lo desea, siempre puede escribir un pequeño envoltorio alrededor de cmath, en las líneas de:

//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;
}

Supongo que podría haber alguna sobrecarga de la llamada a la función adicional, dependiendo de lo inteligente que sea el compilador.

 3
Author: James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-09 17:57:43

Esto es solo un humilde intento de empezar a resolver este problema. (Se agradecen las sugerencias.)

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

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

Esto es en mi opinión es un error molesto o al menos una situación muy desafortunada. (Al menos en GCC, y clang using usando la biblioteca GCC in en Linux.)

Últimamente le di otra oportunidad al problema. Al mirar el cmath (de GCC) parece que el encabezado es simplemente para sobrecargar las funciones C y atornilla el espacio de nombres en el proceso.

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

Con él 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<cmath> pero la mayoría de las funciones parecen funcionar.

Lo peor de todo es que eventualmente alguna biblioteca de dependencia eventualmente será #inclulde<cmath>. Para eso no pude encontrar una solución todavía.

NOTA : No hace falta decir que esto no funciona en absoluto

namespace std{
   #include<cmath> // compile errors
}
 1
Author: alfC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-13 05:53:48