views:

176

answers:

4

Hi,

I have been reading articles about unnamed namespaces the whole day, most articles explained when you should use unnamed namespaces over the static keyword. But I am still left with one big question when is it appropriate to use static? After all it is not completely deprecated, what about header files with static functions should I put them into unnamed namespaces now?

#ifndef HEADER_H
#define HEADER_H

static int func() {
  ...
}

// versus:

namespace {
  int func() {
    ...
  }
};

#endif // HEADER_H 

Or what about static member functions?

Greetings

+2  A: 

There is no advantage of static in namespace scope over unnamed namespaces which I know of. Use unnamed namespaces, as in the example above. Actually in the example above I can't see why is static or unnamed namespace necessary. Maybe inline? And static member functions have nothing to do with static at namespace scope. Static member functions (and nonfunction members) are still valid.

Armen Tsirunyan
In the example the static is needed in order to avoid the function having external linkage. As it will be implemented in every module that uses the header, the linker might object if the static keyword is not present.
Alexander Rautenberg
@Alexander: Well, inline will allow multiple definitions of the function. And in my opinion is a superior alternative. However, if "INTERNAL LINKAGE" is exactly what is needed, then unnamed namespace is much better, at least because it is not deprecated.
Armen Tsirunyan
@Armen: `inline` allows multiple *identical* definitions of the function. `static` allows multiple different definitions, since each translation unit has its own function with internal linkage, they just happen to be referred to by the same name. So, if there's something in the definition of `func` that depends on some #defines (such as `assert`), and you want it to be legal to combine different TUs that included the header with different values in the #define, then you'd need either `static` or an unnamed namespace. `inline` won't do, officially, although in practice it might work.
Steve Jessop
@Armen: If _internal linkage_ is **exactly** what is required then an unnamed namespace is not sufficient. While it may be a technicality, members of an unnamed namespace (other than other namespaces) have _external linkage_ by default.
Charles Bailey
My FCD says "Although entities in an unnamed namespace might have external linkage, they are effectively qualified by a name uniqueto their translation unit and therefore can never be seen from any other translation unit."
Ben Voigt
+3  A: 

The precise wording of the standard is:

The use of the static keyword is deprecated when declaring objects in namespace scope.

Functions in a header file should be inline rather than static or in an unnamed namespace. Inline linkage means you will only end up with at most one copy of the function in your program, while the other methods will give you a separate copy from each file that includes the header. As well as bloat, this could give incorrect behaviour if the function contains function-static data. (EDIT: unless the function is supposed to have different definitions in different compilation units, perhaps due to different preprocessor macros that are defined before including the header file. In that case the best approach is not to include it at all, but rather to bury it in an unmarked grave with a stake through its unholy heart.)

Data objects, apart from constants, usually shouldn't be defined in header files at all, only declared extern.

Static member functions are a different kettle of fish, and you have to use static there as there is no other way to declare them. That usage isn't deprecated, since it isn't in namespace scope.

Mike Seymour
"Data objects shouldn't be defined in header files at all, only declared extern if they need external linkage." This is imprecise. "Data object", as you call them, have external linkage by default, unless they're const. So extern is needed to make their declaration just a declaration and not a definition, which is the default. However if both extern and an initializer are present, it is a definition.
Armen Tsirunyan
Data objects often need to be defined in header files. That includes constants (which are objects). I guess it's good advice for C++ novices to avoid defining (static class member) constants of non-integral types in header files. More experienced programmers can do that using e.g. the templated constants trick. Another such trick is a function returning a reference to a local static constant.
Alf P. Steinbach
@Armen, @Alf: yes, my advice concerning data objects was a bit simplistic. I'll rephrase it.
Mike Seymour
OK, good explanation for external and static member functions. Concerning inline I always thought it would replace the function calls with the function code itself and thus I end up with a lot of copies?!
haribo
@haribo: The definition of an inline function is allowed and REQUIRED in all the translation units in which the function is used. So it's a great way to make sure you won't get linker errors when you define a function in a .h file (note that when a member function is defined lexically INSIDE the class, it is implicitly inline). The replacing of the function calls with the code itself is an optional thing which the comiler can choose to do or ignore.
Armen Tsirunyan
@haribo: on most compilers, `inline` will make no difference to whether a function gets inlined or not; you can end up with multiple (inlined) copies of any function that the compiler decides to inline. The purpose of `inline` is to give the function inline linkage; this means that you are allowed identical definitions in multiple compilation units, and only one copy ends up in the final program. Using `static` or an nameless namespace will give identical definitions of *different* functions, all of which will end up in the final program.
Mike Seymour
@Mike: your answer helped a lot, thanks.
haribo
@Mike: regarding inline. Better make sure that all definitions of the function (across the various objects) is the same, because of ODR the linker will probably never bother to check and just assume so.
Matthieu M.
@Matthieu: good point; I've added my opinion of header file functions that might differ between compilation units.
Mike Seymour
"or in an unnamed namespace." - nooo that's utterly bad. Unnamed namespaces are for .cpp files that want to make data, functions or types TU-local. So that they can use common names and are guaranteed to not conflict. But if you place them into the header, you pollute that private environment!
Johannes Schaub - litb
+2  A: 

In a header file there's usually no point in specifying internal linkage, or using an anonymous namespace.

In a separately compiled implementation file you can use static or an anonymous namespace to avoid linkage level name collisions or client code relying on implementation details. An anonymous namespace lets you have external linkage, which is required for template parameters, and it also supports class definitions. But in the end it's just a question of practicality and personal preference, on a case by case basis.

static for a member function has nothing to do with linkage specification. A static member function has external linkage anyway.

Alf P. Steinbach
A: 

static can be preferable if you are using some tools. It also behaves a bit better with auto indent functionality in most text editors. It's a bit sad, when you have to avoid using something useful because it doesn't work with tools that should really support it, but I promise you'll get over it.

An example question that gives some hint of potential pain in the debugging department:

http://stackoverflow.com/questions/2983316/viewing-namespaced-global-variables-in-visual-studio-debugger

You probably won't have to look very hard to find more problems, but the debugger issues were enough to make me entirely give up on namespaces, to the maximum extent possible, so I've never looked any further.

My personal recommendation is that for code that will be around for less than forever, one might as well go with static. Does effectively the same thing as an unnamed namespace, but, averaged out over all tools, it is better supported. In theory, one day it will disappear completely, but I'm happy to publicly admit that I'm certain that day will never actually come to pass. And in the mean time, you are saving yourself some pain.

brone