12

if I define a namespace log somewhere and make it accessible in the global scope, this will clash with double log(double) from the standard cmath header. Actually, most compilers seem to go along with it -- most versions of SunCC, MSVC, GCC -- but GCC 4.1.2 doesn't.

Unfortunately, there seems no way to resolve the ambiguity, as using declarations are not legal for namespace identifiers. Do you know any way I could write log::Log in the global namespace even if cmath is included?

Thanks.

EDIT: Would anybody know what the C++03 standard has to say about this? I would have thought that the scope operator sufficiently disambiguates the use of log in the code example below.

#include <cmath>

namespace foo
{

namespace log
{

struct Log { };

} // namespace log

} // namespace foo


using namespace foo;

int main()
{
    log::Log x;

    return 0;
}

// g++ (GCC) 4.1.2 20070115 (SUSE Linux)

// log.cpp: In function `int main()':
// log.cpp:20: error: reference to `log' is ambiguous
// /usr/include/bits/mathcalls.h:110: error: candidates are: double log(double)
//     log.cpp:7: error:                 namespace foo::log { }
// log.cpp:20: error: expected `;' before `x'
cj.
  • 250
  • 1
  • 3
  • 13
  • Why not just write it as `foo::log::Log` to prevent the ambiguousity? – reko_t Oct 06 '10 at 10:25
  • `Log` is not the only member of `foo::log`, there are lots of these. But yes, I'll probably end up fully qualifying all of these if there is no other way. – cj. Oct 06 '10 at 10:28
  • @cj: You might want to have a look at [this answer](http://stackoverflow.com/questions/2879555/c-stl-how-to-write-wrappers-for-cout-cerr-cin-and-endl/2880136#2880136). – sbi Oct 06 '10 at 10:34
  • 1
    Shouldn't C identifiers imported through the `` versions of C standard headers be located in the `std` namespace? Is it a v4.1 implementation bug (in g++ 4.4 this code works fine) or I remember this thing wrong? – Matteo Italia Oct 06 '10 at 10:54
  • 1
    @Matteo Italia: These identifiers are required to be also accessible in the global namespace. See http://stackoverflow.com/questions/1524139/ansi-c-functions-namespace-in-iso-c/1524387#1524387 . – cj. Oct 06 '10 at 11:24
  • 2
    @cj: as far as I understand from those standard quotations, as far as the standard is concerned these identifiers have to be put in the global namespace only if you include the `` C header, while including `` should put them only in the `std` namespace. – Matteo Italia Oct 06 '10 at 11:47
  • @Matteo: you're right, I misread. – cj. Oct 06 '10 at 16:01
  • 1
    I found this bug to be very annoying, I could patch `/usr/include/bits/mathcalls.h` but then the file `` expects `log` for example to be in the global namespace (see line 356 in gcc's stdlib ``, it reads `using ::log;`. I wonder if one can play with all the defined macros in order to correct all this behavior. By the way, @MatteoItalia, I find this also in gcc 4.7, so if it was fixed in 4.4 the bug came back. – alfC May 16 '13 at 06:02

4 Answers4

13

I'd suggest:

foo::log::Log x; // Your logging class
::log(0.0); // Log function

Generally I wouldn't write using namespace foo; as there is no point having it in the foo namespace if you're not going to use it and it pollutes the global namespace.

See this related question:
How do you properly use namespaces in C++?

Community
  • 1
  • 1
Mark Ingram
  • 71,849
  • 51
  • 176
  • 230
9

Although it does not help you, the error from GCC 4.1.2 is incorrect. The log in log::Log can only refer to a class or namespace name.

If your code also needs to compile with GCC 4.1.2, then there are two options:

  1. Use the fully qualified name foo::log::Log
  2. Use a namespace alias:

    namespace log1 = foo::log;
    log1::Log logger;
Bart van Ingen Schenau
  • 15,488
  • 4
  • 32
  • 41
  • 1
    +1 for the idea of using an alias. Are you sure the error is incorrect? I presume you mean that the scope operator resolves the ambiguity because it cannot be applied to a function name? I'm not sure what the standard says about this special case. But regarding namespace definitions, see section 7.3.1: "The identifier in an original-namespace-definition shall not have been previously defined in the declarative region in which the original-namespace-definition appears." – cj. Oct 06 '10 at 10:51
  • 1
    I am sure the error is incorrect. I had to look it up in the standard, and according to the grammar only a class or namespace name can occur before the scope operator. The declaration of your `log` namespace is not a problem, because it is not being defined in the same namespace as the `log` function. (namespace is withing `foo` namespace, function is in global namespace) – Bart van Ingen Schenau Oct 06 '10 at 14:01
1

cmath uses ::log for some reason to get it from the global scope and can't decide between the function and your namespace.

Namespaces keep code contained to prevent confusion and pollution of function signatures.

Here's a complete and documented demo of proper namespace usage:

#include <iostream>
#include <cmath>  // Uses ::log, which would be the log() here if it were not in a namespace, see https://stackoverflow.com/questions/11892976/why-is-my-log-in-the-std-namespace

// Silently overrides std::log
//double log(double d) { return 420; }

namespace uniquename {
    using namespace std;  // So we don't have to waste space on std:: when not needed.

    double log(double d) {
        return 42;
    }

    int main() {
        cout << "Our log: " << log(4.2) << endl;
        cout << "Standard log: " << std::log(4.2);
        return 0;
    }
}

// Global wrapper for our contained code.
int main() {
    return uniquename::main();
}

Output:

Our log: 42
Standard log: 1.43508
Community
  • 1
  • 1
Cees Timmerman
  • 17,623
  • 11
  • 91
  • 124
0

In c++0x or c++11, the following should work, compile with -std=c++0x or -std=c++11:

#include <iostream>
#include <math.h>

namespace ___ {
namespace log {

void init() {
    std::cout << "log::init()" << std::endl;
}

} // namespace log
} // namespace ___

using namespace ___;

int main() {
    log::init();
    std::cout << ::log(3.2) << std::endl;
    return 0;
}
idealvin
  • 178
  • 1
  • 5