Why can static member function definitions not have the keyword 'static'? - c++

As per this link on the 'static' keyword in C++ :
The static keyword is only used with the declaration of a static
member, inside the class definition, but not with the definition of
that static member.
Why is the static keyword prohibited on member function definitions? I do understand that re-declaring a function as 'static' at its definition is redundant. But using it should be harmless during compilation of the function definition as it does not result in any kind of ambiguity. So why do compilers prohibit it?

There's ambiguity alright. The same definition need not be for a member function at all.
Consider this:
namespace foo {
static void bar();
}
static void foo::bar() {
}
foo::bar is required to be defined with the same linkage specifier.
For member functions, however, static is not a linkage specifier. If it was allowed, the correctness of the definition of foo::bar will be very very context dependent on what foo is. Disallowing static in fact eases the burden on the compiler.
Extending it to members in general, as opposed to just member functions, is a matter of consistency.

The point is, that static has several, very different meanings:
class Foo {
static void bar();
}
Here the static keyword means that the function bar is associated with the class Foo, but it is not called on an instance of Foo. This meaning of static is strongly connected to object orientation. However, the declaration
static void bar();
means something very different: It means that bar is only visible in file scope, the function cannot be called directly from other compilation units.
You see, if you say static in the class declaration, it does not make any sense to later restrict the function to file scope. And if you have a static function (with file scope), it does not make sense to publish it as part of a class definition in a public header file. The two meanings are so different, that they practically exclude each other.
static has even more, distinct meanings:
void bar() {
static int hiddenGlobal = 42;
}
is another meaning, that is similar, but not identical to
class Foo {
static int classGlobal = 6*7;
}
When programming, words don't always the same meaning in all contexts.

You have to understand the difference between declaration and implementation, and that will answer your question:
Declaration: Is how C++ functions and methods are seen before compiling the program. It's put in a header file (.h file).
Implementation: Is how the compiler links a declaration to a real task in binary code. The implementation can be compiled on the fly (from source files, .cpp or .cxx or .cc), or can be already compiled (from shared libraries or object files).
Now going back to your question, when you declare something as static, it's something not related to the implementation, but related to how the compiler sees the decleration while compiling the code. For example, if you label functions in source files "static", then that's meaningless, because that information cannot be carried to compiled objects and shared libraries. Why allow it? On the contrary, it could only cause ambiguity.
For the exact same reason, default parameters must go into the header, not the source files. Because source files (that contain implementations), cannot carry the default parameter information to a compiled object.

Wild guess but if the definition has static it could be interpreted as a file-scope variable in the C sense.

Related

How can I prevent static class member variables from needing two definitions/declarations?

I don't think this is a duplicate because other questions ask why it's necessary, not how I can avoid writing it twice.
Often with classes I'll introduce member variables and then, for whatever reason, remove them shortly after if I don't like them.
With a non-static member variable I can simply add a member to the header file and use it in my code immediately. With a static member variable I have to do the following:
Add the new member to the class definition, e.g. static int a;.
Copy the new member declaration.
Go to a .cpp file (any .cpp file will do if I understand right).
Paste the variable in the file.
Remove the static keyword.
Add the class namespace/scope after the type and before the variable name.
All of this makes me want to just make all of my classes instantiable and do everything through an object, even if it wouldn't make sense.
So even if this is just a requirement of the language and there is no way around it, is there a way to cut back on the repetition by using macros in some way?
Also I was thinking if maybe it mightn't be simpler to just have one .cpp file containing all of these static member variable definitions. Seeing as though (I've heard) static member variables are basically global variables accessed through a class namespace, is this a better idea than doing it in each corresponding .cpp file?
I'm going to provide a solution for integral types (since you highlight those types in your question):
struct Foo
{
enum {Value = 123;}
};
Value can be used as an integral constant, is the same for all instances of Foo (rather like a static) and does not require definition in a source file. Note though that &Value makes no sense, i.e. there's no such thing as a pointer to an enumeration value.
You can do things with constexpr in later C++ standards (C++11 onwards), but my way is arguably simpler and is also an important metaprogramming technique.
(If this is not sufficient for what you want then please downvote and I'll remove.)
A possibility is too use static in function scope, something like:
struct C {
static int& a() {
static int a_instance = 42;
return a_instance;
}
};

Why would a non-constant static member have multiple definitions?

C++ forces the programmer to define a non-constant static member outside the class, and the reason for this that I keep seeing is that if the static member was defined inside the class,
this would result in multiple definitions for the static member. I understand that having
multiple definitions for a static member is bad, but I don't understand where these multiple
definitions would even come from. Shouldn't an initialized non-constant static member
just go in the data section and that be the only definition?
struct Student {
static int x = 4; // Why would this result in multiple definitions?
};
Also, I read in this other stackoverflow post that const static members are simply inlined into the code wherever it is used:
Why can't I have a non-integral static const member in a class?
Is that handled by the preprocessor along with all the other directives? ( I will ask this in another post if needed, but I
wasn't sure if it's worthy of a separate post ).
It would happen because/when your header gets included in multiple "translation units" (think .cpp files).
Each TU will then contain a copy of the definition.
At link time, they will clash. (The linker links the objects from each translation unit)

Why is a static const in the header defined as const in the code file

If I am correct a static constant member in a class is defined like this:
// header file, inside a class definition:
static const SomeType my_const;
// cpp file
const ClassName::SomeType my_const = SomeType(5.0);
Now I don't understand why the classifier is not present in the cpp file. The signature doesn't match so to say, and I don't want to OCD over it too much but what is the reasoning behind this?
For the curious, when I do add static this is the error message I get:
error C2720: 'static ' storage-class specifier illegal on members
static is a massively overloaded keyword, it has at least 4 different meanings and more to look after. No wonder you are confused.
Your first line is not just standing in the header, but is within a class. (please edit the code). In a class you can have normal members, and ones that are shared between instances. To mark that static was the choice.
At namespace scope the keyword means completely different thing, namely it turns the linkage to internal. As definition ios made at that scope you must not add that "version" of static.
const SomeType ClassName::my_const = SomeType(5.0);
I strongly doubt that is it -
const ClassName::SomeType my_const = SomeType(5.0);
OR const SomeType ClassName::my_const = SomeType(5.0);
In very simple terms:-
'static' is a storage type its not a data type or a modifier, here it was just to tell the compiler that this should be shared in all the instances of the object which means to create only one instance of it. We do not include storage type in the signatures.

Declaring static data members of normal class and class template

I read the reason for defining static data members in the source file is because if they were in the header file and multiple source files included the header file- the definitions would get output multiple times. I can see why this would be a problem for the static const data member, but why is this a problem for the static data member?
I'm not too sure I fully understand why there is a problem if the definition is written in the header file...
The multiple definition problem for variables is due to two main deficiencies in the language definition.
As shown below you can easily work around it. There is no technical reason why there is no direct support. It has to do with the feature not being in sufficient high demand that people on the committee have chosen to make it a priority.
First, why multiple definitions in general are a problem. Since C++ lacks support for separately compiled modules (deficiency #1), programmers have to emulate that feature by using textual preprocessing etc. And then it's easy to inadvertently introduce two or more definitions of the same name, which would most likely be in error.
For functions this was solved by the inline keyword and property. A freestanding function can only be explicitly inline, while a member function can be implicitly inline by being defined in the class definition. Either way, if a function is inline then it can be defined in multiple translation units, and it must be defined in every translation unit where it's used, and those definitions must be equivalent.
Mainly that solution allowed classes to be defined in header files.
No such language feature was needed to support data, variables defined in header files, so it just isn't there: you can't have inline variables. This is language deficiency #2.
However, you can obtain the effect of inline variables via a special exemption for static data members of class templates. The reason for the exemption is that class templates generally have to be fully defined in header files (unless the template is only used internally in a translation unit), and so for a class template to be able to have static data members, it's necessary with either an exemption from the general rules, or some special support. The committee chose the exemption-from-the-rules route.
template< class Dummy >
struct math_
{
static double const pi;
};
template< class Dummy >
double const math_<Dummy>::pi = 3.14;
typedef math_<void> math;
The above has been referred to as the templated const trick. As far as I know I was the one who once introduced it, in the [comp.lang.c++] Usenet group, so I can't give credit to someone else. I've also posted it a few times here on SO.
Anyway, this means that every C++ compiler and linker internally supports and must support the machinery needed for inline data, and yet the language doesn't have that feature.
However, on the third hand, C++11 has constexpr, where you can write the above as just
struct math
{
static double constexpr pi = 3.14;
};
Well, there is a difference, that you can't take the address of the C++11 math::pi, but that's a very minor limitation.
I think you're confusing two things: static data members and global variables markes as static.
The latter have internal linkage, which means that if you put their definition in a header file that multiple translation units #include, each translation unit will receive a private copy of those variables.
Global variables marked as const have internal linkage by default, so you won't need to specify static explicitly for those. Hence, the linker won't complain about multiple definitions of global const variable or of global non-const variables marked as static, while it will complain in the other cases (because those variables would have external linkage).
Concerning static data members, this is what Paragraph 9.4.2/5 of the C++11 Standard says:
static data members of a class in namespace scope have external linkage (3.5). A local class shall not have
static data members.
This means that if you put their definition in a header file #included by multiple translation units, you will end up with multiple definitions of the same symbol in the corresponding object files (exactly like non-const global variables), no matter what their const-qualification is. In that case, your program would violate the One Definition Rule.
Also, this Q&A on StackOverflow may give you a clearer understanding of the subject.

Linkage of classes

Do classes have external linkage? If so, why couldn't I get the following to work on gcc?
// mycpp1.cpp
class MyClass
{
int x;
// ......
};
`
// mycpp2.cpp
class MyClass; // why doesn't this work?
I've done some googling around and came around this,
C++ Standard
(3.5/4) a named class (clause 9), or an unnamed class defined in a
typedef declaration in which the class has the typedef name for
linkage purposes (7.1.3);
I could just include the file, but what would be the purpose of linkage?
Why I half agree with Nawez that you shouldn't worry too much about
linkage, it is nice to understand it, so you know why the coding pattern
you're using works (and why other patterns don't). Linkage defines how
a name (a symbol) is bound to an entity (variable, function, type,
etc.). External linkage means that the name (or the qualified version
of it) binds to the same entity in all of the translation units: in your
case, that MyClass is the same class in all of the translation units.
It doesn't mean that all translation units automatically know how it is
defined; just that MyClass in mycpp1.cpp is the same type as
MyClass in mycpp2.cpp. For various reasons related to compiler and
linker technology, you still have to provide a definition in every source
(preferably by means of an include) that uses it, but these definitions
are required to be identical (which is why the include is preferred),
because the compiler will generate code treating them as identical.
You should be doing this:
Header File : declaration should go in .h file
// mycpp1.h
class MyClass
{
int x;
void f(); //only declaration
};
Source File : : definition should go in .cpp file
// mycpp1.cpp
#include "mycpp1.h"
void MyClass::f() //definition of member function
{
//code
}
and then use MyClass as
// mycpp2.cpp
#include "mycpp1.h"
MyClass instance; // it should work!
I would suggest you to pick a good introductory book on C++. Here is a comprehensive list of good books on C++:
The Definitive C++ Book Guide and List
class MyClass; // why doesn't this work?
This is a forward declaration - it declares that the class exists, but doesn't provide the information needed to do much with it.
With just a forward declaration, you can do a few things, including declaring a pointer or reference to it, and declaring a function with it as an argument or return value. You can't instantiate it, inherit from it, access any of its members, or do various other things without the full definition, for which you need to include the header file.
I could just include the file, but what would be the purpose of linkage?
A header file often contains declarations of functions and objects, which can then be fully defined in a separate source file and not included by files using them. That is the purpose of linkage, but it doesn't extend to allowing class definitions to be in separate source files.