The role of C++ anonymous namespace and the difference from static

The role of anonymous namespace and its difference from static

one. The role of anonymous namespace
In the C language, if we use the same name as
a function name or global variable name in multiple tu (translation units), a redefinition error will occur during the linking phase. In order to solve this
problem, We can define these identifiers (identifier) ​​with the static keyword modifier
to restrict it to be visible only within a tu scope.
C++ inherits the use of the static keyword in the C language, and we can still use static to avoid
the redefinition problem caused by using the same identifier in multiple tu. In addition, C++ also provides another unique
way, which is anonymous namespace: a namespace without a specified name is called an anonymous
namespace; multiple anonymous namespaces can appear in a tu, and anonymous namespaces at the same level are
actually are synthesized into the same; the same identifiers appearing in anonymous namespaces of different tu
are independent of each other and will not conflict, so we can put those
global identifiers that only want to be visible in the same tu scope into an anonymous namespace, The effect is the same as adding static before.

two. The difference between anonymous namespace and static
After a global identifier is modified by static, its linkage becomes internal linkage, which is
why the same identifier in different tu will not conflict.
The anonymous namespace does not change the linkage of the identifiers defined in it. The method it uses to avoid
name conflicts is exactly the same as the method used by C++ to implement overloading, which is to
use name mangling. : According to C++ Standard 7.3.1.1, the anonymous namespace in each tu
will actually have a unique name, so the same
identifiers actually belong to different namespaces. There will be a conflict:

7.3.1.1 Unnamed namespaces [namespace.unnamed]
An unnamed-namespace-definition behaves as if it were replaced by
namespace unique { /* empty body */ }
using namespace unique;
namespace unique { namespace-body }
where all occurrences of unique in a translation unit are replaced
by the same identifier and this identifier differs from all other
identifiers in the entire program.

Why don't anonymous namespaces take the same approach as static? Wouldn't a new trick increase
the burden of compiler development? This is actually due to another C++ feature that hampers the
implementation of anonymous namespaces, namely template non-type arguments:

14.3.2 Template non-type arguments [temp.arg.nontype]
A template-argument for a non-type, non-template template-parameter
shall be one of:
— an integral constant-expression of integral or enumeration type; or
— the name of a non-type template-parameter; or
— the address of an object or function with external linkage, including
function templates and function template-ids but excluding non-static
class members, expressed as & id-expression where the & is optional
if the name refers to a function or array, or if the corresponding
template-parameter is a reference; or
— a pointer to member expressed as described in 5.3.1 .

It is the requirement of external linkage marked in red that limits the realization of anonymous namespace!
Just imagine, what if we have a global object or function that we only want to be available in a tu, and
we want to be able to instantiate a template with its address? Only valid in one tu, you can
choose internal linkage, but use its address as a template parameter, and it must be
external linkage! !
Obviously, the property of anonymous namespace does not change the linkage of its internal identifier solves this
problem, we can safely throw this global object or function in an anonymous namespace, and
then use its address to instantiate a template, Absolutely no redefinition errors occur :)

Most C++ books nowadays consider anonymous namespace and static to be the same, and as explained here
, the difference between them is obvious: static-modified identifiers
cannot be used to instantiate templates due to the limitation of internal linkage !

Finally, an example is given to confirm that the anonymous namespace does not change the linkage, huh
, the three cases of external linkage/internal linkage/no linkage are verified in the code
——————————————————

template
struct foo
{
void bar();
};

static char a =’a’;

namespace
{
char b = ‘b’;
static char c = ‘c’;

template struct xxx {};

void foobar()
{
struct no_linkage {};
xxx<no_linkage>(); // If there is an error in compilation, the linkage of no_linkage has not changed
}
}

int main()
{
foo<&a>().bar(); // since a's linkage is internal, it should compile with an error
foo<&b>().bar(); // if it compiles correctly, Explain that the linkage of b is external
foo<&c>().bar(); // If the compilation is wrong, the linkage of c is internal

foobar();

return 0;
}

———————————————————
Comeau C/C++ 4.3.3 (Aug 6 2003 15:13:37) for ONLINE_EVALUATION_BETA1
Copyright 1988-2003 Comeau Computing. All rights reserved.
MODE:strict errors C++

“ComeauTest.c”, line 19: error: a template argument may not reference a
local type
xxx<no_linkage>();
^
^

“ComeauTest.c”, line 25: error: a template argument may not reference a
non-external entity
Hint: http://www.comeaucomputing.com/techtalk/templates/#stringliteral
foo<&a>().bar();
^

“ComeauTest.c”, line 27: error: a template argument may not reference a
non-external entity
Hint: http://www.comeaucomputing.com/techtalk/templates/#stringliteral
foo<&c>().bar();
^

3 errors detected in the compilation of “ComeauTest.c”.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325233480&siteId=291194637