2

Can someone explain why I can't define variable that was declared in anonymous namespace as global variable in another place?

#include <iostream>
namespace  {
    extern int number;
}

int number = 123;

void g() {
    std::cout << number;
}

Compiler says that "Reference to 'number' is ambiguous" but I can't understand why it recognises declaration and definition as different things? Thank you in advance.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
notamaster
  • 53
  • 4

2 Answers2

2

In general, the name being declared by a declaration is not looked up—after all, you can’t rely on finding a previous declaration when a name is first introduced. Of course, there is a similar process that traps things like

int x;
float x;

However, since it isn’t lookup it is not affected by using at all (including for an unnamed namespace). Another way of describing this distinction is that a declaration puts entities into namespaces and thus need not consider any other namespace in order to decide where to put an entity.

There are also cases where lookup does occur for (what might be) a declarator-id:

namespace N {using X=int;}
// using namespace N;
struct A {
  A(X());  // ?
};

A has a member function with no parameters returning an A named X (with meaningless parentheses around its declarator); however, with the using-directive it instead has a constructor that takes a pointer to a function of no parameters returning an int. Similarly, in a declaration beginning

template<>
struct X<…

X must be fully looked up, even though a declaration of an explicit specialization must inhabit the same scope as the primary template (with leeway for inline namespaces), because it might continue

template<>
struct X<int>::Y<char> {…};

and not be a specialization of X at all.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76
1

For the unqualified name-lookup the compiler considers also nested unnamed namespaces in the global namespace,

You declared two different objects with the same name in the global namespace and in the nested unnamed namespace.

The using directive for unnamed namespace is implicitly inserted in the enclosing namespace.

Consider the following demonstration program

#include <iostream>

namespace N
{
    extern int number;
}

using namespace N;

int number = 123;

int main()
{
    std::cout << number << '\n';
}

The compiler will issue an error due to the ambiguity for the unqualified reference to the name number in this statement

std::cout << number << '\n';

The similar situation takes place with an unnamed namespace because the using directive is implicitly inserted in the enclosing namespace.

From the C++ 20 Standard (9.8.2 Namespace definition)

7 Members of an inline namespace can be used in most respects as though they were members of the enclosing namespace. Specifically, the inline namespace and its enclosing namespace are both added to the set of associated namespaces used in argument-dependent lookup (6.5.3) whenever one of them is, and a using directive (9.8.4) that names the inline namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace (9.8.2.2).

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • But why it doesn't consider variable from unnamed namespace only as declaration? – notamaster Jul 21 '22 at 22:18
  • 1
    @notamaster It considers. So you have two declarations with the same name: one in the unnamed namespace and other in the enclosing global namespace. So for this statement std::cout << number; there is an ambiguity for the unqualified name lookup. – Vlad from Moscow Jul 21 '22 at 22:19
  • I mean, for example, if I wouldn't write declaration of variable in unnamed namespace and just write `extern int number` and then `int number = 5` it will be ok(I wrote a declaration of variable and then defined it). But it doesn't work in unnamed namespace. – notamaster Jul 21 '22 at 22:24
  • 1
    @notamaster You have to declare and define a variable in the same namespace. `::number` and `::number` are different variables, so the latter is not a definition of the former. – Miles Budnek Jul 21 '22 at 22:26