C structure and C function with the same name in C++

Viewed 147

When I was mixing C and C++ code I ran into a problem when Linux C struct statx has same name as statx() Linux system call.

For the case that statx() system call is not present in the installed glibc version, I implement my own version of statx(). I tried to implement an alternate statx() function in the anonymous namespace, but the code does not compile in this case.

I tried to simplify the sample code to a minimum of complexity.

#include <iostream>

struct statx {};

namespace {

void statx() { std::cout << "Function statx()\n"; }

}

int main()
{
    statx();    // Compile error.
    ::statx();  // Calling constructor of struct instead of function statx().
}

The output of compilation with g++ 8

g++ -std=c++17 -Wall -pedantic -Wextra str_fnc.cpp -o str_fnc


str_fnc.cpp: In function 'int main()':
str_fnc.cpp:13:5: error: reference to 'statx' is ambiguous
   13 |     statx();    // Compile error.
      |     ^~~~~
str_fnc.cpp:7:6: note: candidates are: 'void {anonymous}::statx()'
    7 | void statx() { std::cout << "Function statx()\n"; }
      |      ^~~~~
str_fnc.cpp:3:8: note:                 'struct statx'
    3 | struct statx {};
      |        ^~~~~
str_fnc.cpp: At global scope:
str_fnc.cpp:7:6: warning: 'void {anonymous}::statx()' defined but not used [-Wunused-function]
    7 | void statx() { std::cout << "Function statx()\n"; }
      |      ^~~~~

When I use static function statx() instead of including it in the anonymous namespace, the code compiles and works successfully.

#include <iostream>

struct statx {};

static  // The replacement anonymous namespace with static function.
void statx() { std::cout << "Function statx()\n"; }

int main()
{
    statx();
    ::statx();
}

Can anyone explain why the sample with statx() included in the anonymous namespace does not compile and not work?

1 Answers

Name hiding [basic.scope.hiding]
2. If a class name ([class.name]) or enumeration name ([dcl.enum]) and a variable, data member, function, or enumerator are declared in the same declarative region (in any order) with the same name (excluding declarations made visible via using-directives ([basic.lookup.unqual])), the class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is visible.

So in your second example, the two names are declared in the same declarative region, and the function hides the struct name. (You can still refer to the struct by its elaborated-type-specifier struct statx).

In the first example, the function is introduced in a different declarative region, so this provision does not apply. Instead, normal namespace rules are in effect. Namely, the inner name is brought, as if by a using-declaration, to the global scope. If you have the same name declared both inside and outside of an unnamed namespace, then the name becomes ambiguous when unqualified. You can select the outer name with a ::, but there is no way to refer to the inner name from the outside of the unnamed namespace.

Related