Home > database >  Why can't the using keyword be used for a forward declaration when defining a function?
Why can't the using keyword be used for a forward declaration when defining a function?

Time:12-08

Given the following header and source, in which a simple function GiveMeATwo is forward declared in the header test.hpp, within the namespace SomeNamespace, why does a conflict occur when trying to bring the function GiveMeATwo into scope via using SomeNamespace::GiveMeATwo, prior to defining GiveMeATwo?

test.hpp

#ifndef _TEST_HEADER_
#define _TEST_HEADER_

namespace SomeNamespace {
    int GiveMeATwo();
}

#endif

test.cpp

#include "test.hpp"

using SomeNamespace::GiveMeATwo;

int GiveMeATwo() {
    return 2;
}

Compiling with Apple clang version 14.0.0 (clang-1400.0.29.202) yields the following error, indicating that the using statement somehow implicitly introduces a declaration?

test.cpp:5:5: error: declaration conflicts with target of using declaration already in scope
int GiveMeATwo() {
    ^
./test.hpp:6:5: note: target of using declaration
int GiveMeATwo();
    ^
test.cpp:3:22: note: using declaration
using SomeNamespace::GiveMeATwo;
                     ^
1 error generated.

Furthermore, what is the difference between bringing the GiveMeATwo symbol into scope via using namespace SomeNamespace, versus using SomeNamespace::GiveMeATwo as I have done here?

CodePudding user response:

To quote cppreference:

If an entity is declared, but not defined in some inner namespace, and then declared through using-declaration in the outer namespace, and then a definition appears in the outer namespace with the same unqualified name, that definition is a member of the outer namespace and conflicts with the using-declaration

In other words, this definition:

int GiveMeATwo() {
    return 2;
}

is for another function. If you want to define the one in SomeNamespace, you still need to name the namespace, even if you wrote using SomeNamespace::GiveMeATwo; or using namespace SomeNamespace; before it:

int SomeNamespace::GiveMeATwo() {
    return 2;
}

Demo

The using-directive (using namespace) is slightly different because:

Using-directive does not add any names to the declarative region in which it appears (unlike the using-declaration), and thus does not prevent identical names from being declared.

So you can do this:

namespace SomeNamespace {
    int GiveMeATwo();
}

using namespace SomeNamespace;

int GiveMeATwo() {
    return 2;
}

but it's somewhat useless because a call to GiveMeATwo is now ambiguous unless you qualify it, like ::GiveMeATwo(); for the outer function or SomeNamespace::GiveMeATwo(); for the inner one.

  • Related