I have come across different macros which enable deprecation of member attributes and functions but none of them discuss the possibility of deprecating static class members.
I read that even in C++14 deprecation of static members is not allowed.
Is there any specific reason for this?
Let's get some facts:
The wording for the [[deprecated]] attribute is the following
(based on N4269 7.6.5 [dcl.attr.deprecated], emphasis mine):
The attribute may be applied to the declaration of a class, a typedef-name, a variable, a non-static data
member, a function, a namespace, an enumeration, an enumerator, or a template specialization.
The misleading part is the explicit appearance of "non-static data members" without its counterpart at the same level in this list, but in that same list there are two other elements of interest.
The description of a variable is (based on 3 [basic]) :
A variable is introduced by the declaration of a reference other than a non-static data member or of an
object. The variable’s name, if any, denotes the reference or object.
Which means that saying a variable includes static data members
A static member function is a function (a red car is a car, this is a logical conclusion and i don't seem to find anything counter indicating this in the standard).
There isn't any syntax or behaviour problem applying particularly to static members, a static function is pretty much a free function in a namespace and static data member is more or less a global variable in a namespace and you can deprecate free functions and global variables..
As a bonus, it actually works in major compilers.
Summing up all this facts basically means that the [[deprecated]] attribute may actually be applied to a static data member, a non-static data member and a static member function, among other things.
So to answer your question, from my understanding, deprecating static members is actually allowed by the standard.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I know the keyword in c has two usage:
modify variables
modify global variables
this usage limited the scope of global variable range from the point that defined to the end of the file.
modify local variables
this usage limited the scope of local variable in the function that defined, but also remained in the static area of memory
modify functions
this means can only invoke the function in the file it's defined.
and in c++, beside the usage in c, static also used to modify the data member and function member of class. This usage limited the member belong to the class instead of the objects of the class.
I want to know are there anything else usage of static in c/c++?
static is probably the most confusingly overloaded keyword in both C and C++. It means different things in different places.
Within functions, static is a storage class, denoting variables which exist for the lifetime of the programme. So saying
void f() {
static int i = 0;
}
says that the value of i will be preserved between calls to f(). Other storage classes are the default auto (but beware the change in meaning in C++11), extern, and register, plus thread_local in C11/C++11.
At file scope (or namespace scope in C++), static is a linkage specifier. Functions and variables marked static in this way have internal linkage, and so are local to the current translation unit. What this means is that a function like
static int f() {
return 3;
}
can only be referenced by other functions inside the same .c file. This usage of static was deprecated in C++03 in favour of unnamed namespaces. I read somewhere it was undeprecated again in C++11.
In C++, when applied to a member function or member variable of a class, it means that the function or variable does not need a class instance in order to be accessed. There is little different between "class static" member functions/variables and global functions/variable in terms of implementation, except that C++ class access specifiers apply to members.
One last one: in C99 (but not C++), static can be used within an array function parameter, like so:
void f(int a[static 4]) {
}
this specifies that the parameter a must by an integer array of size at least 4.
I think that's all of them, but let me know in the comments if there are any I've forgotten!
Static In the C language family, a static variable is one that exists for the lifetime of a compilation
unit (a source file or module). A static variable can be declared module-wide, and thus be
accessed by all functions defined within the same source file. Such a static variable cannot
be directly accessed from other modules, but inner-module API can pass pointers to static variables and
modify those through pointers. A static variable can also be declared within a function body, where the
usual scope rules apply. A static variable declared within a function is only initialized when
the module is initialized (typically when the application loads), and preserves its values over multiple
invocations of the function that contains the definition.
In C++, a static variable can also be a member of a class definition. Access to a static member
variable is governed by the standard access modifiers (private, public, protected), but all instances of
this class share the same static variable, and share the same value. Modifying the value of this variable
affects all objects of the class. VolatileThe volatile keyword is something all together different, and not in any way
an opposite to static. A static variable may or may not be declared volatile, just as a global or local variable
can be. The volatile keyword is a hint informing the compiler that the variable's value
might change without the compiler's knowledge. Therefore, the compiler's code optimizer cannot make assumptions
about the variable's current value, and must always (re-) read the variable's content.
In reference to c++ -> The static keyword can be used to declare variables, functions, class data members and class functions.
Here are the common usages in different scenarios ( ref from MSDN )
When you declare a variable or function at file scope (global and/or namespace scope), the static keyword specifies that the variable or function has internal linkage. When you declare a variable, the variable has static duration and the compiler initializes it to 0 unless you specify another value.
When you declare a variable in a function, the static keyword specifies that the variable retains its state between calls to that function.
When you declare a data member in a class declaration, the static keyword specifies that one copy of the member is shared by all instances of the class. A static data member must be defined at file scope. An integral data member that you declare as const static can have an initializer.
When you declare a member function in a class declaration, the static keyword specifies that the function is shared by all instances of the class. A static member function cannot access an instance member because the function does not have an implicit this pointer. To access an instance member, declare the function with a parameter that is an instance pointer or reference.
You cannot declare the members of a union as static. However, a globally declared anonymous union must be explicitly declared static.
check following also:
The static keyword and its various uses in C++
static keyword usage
Question
Should I use [[maybe_unused]] attribute on unused class *tors?
Example
Let's consider the following example:
public: struct keyData{
public: [[maybe_unused]] keyData(){};
public: keyData(::std::chrono::steady_clock::time_point timestamp)
: lastMod(timestamp)
{};
protected: ::std::chrono::steady_clock::time_point lastMod = ::std::chrono::steady_clock::now();
};
I want to init multiple keyDatas using cached time_point timestamps. However, I also provide argumentless constructor that inits keyData, setting lastMod to now() as timestamp was not provided.
Should I mark unused public: keyData(){}; with [[maybe_unused]] argument, as in example code, or not?
Research
[[maybe_unused]] description of Standard attributes site says (bold is mine):
Appears in the declaration of a class, a typedef, a variable, a nonstatic data member, a function, an enumeration, or an enumerator. If the compiler issues warnings on unused entities, that warning is suppressed for any entity declared maybe_unused.
Constructors and member initializer
lists
site says (bold is mine):
Constructor is a special non-static member function of a class that is used to initialize objects of its class type.
Destructors
site says (bold is mine):
A destructor is a special member function that is called when the lifetime of an object ends.
operator overloading
site says (bold is mine):
Overloaded operators are functions with special function names.
So if I understood well, *tors are functions, and as functions they can be marked as [[maybe_unused]], can't they?
Should I use [[maybe_unused]] attribute on unused class *tors?
The purpose of [[maybe_unused]] is to prevent the emission of warnings for compilers that might warn about the qualified item being unused. Does your compiler warn about unused constructors? If so, then you should use it to suppress that warning.
But since most compilers don't warn about disused functions, it's best not to bother. The attribute would just be taking up space.
Unless you're advertising your library as being -Wunused-member-function clean, it's probably best for all involved that you not suppress this warning. After all, users who want to use that warning actually want the warning to be there. And users who don't use the warning don't need [[maybe_unused]] to be sprinkled around seemingly at random.
The standard says,
"A member of a class T cannot use T as its name if the member is a static data member, a member function, a member type, a member template, an enumerator of an unscoped enumeration, a member of a member anonymous union. However, a non-static data member may use the name T as long as there are no user-declared constructors."
However if I create this class, it gives an compile error.
class G
{
int G;
};
I am using VS2013. Is it not allowed in Microsoft or ?
If VC++ doesn't allow this, it's a bug.
However, this language "feature" is for the purpose of C compatibility, and Microsoft has decided not to emphasize C. For example, C99 features are unavailable as a rule until adopted by C++. You should never purposely declare such a member in C++.
(It's allowed in C simply by default: there are no restrictions on the naming of members, and all members are nonstatic data members.)
In C++ 5.1.1/3 [expr.prim.general] it says:
The type and value category [of this] are defined within a static member function.
What does this mean? How is it relevant?
Note that:
this shall not appear in the declaration of a static member function
The language in the standard can be traced to n3282, which is a resolution for defects 1207 and 1017. In particular, the language appears in the proposed resolution for defect 1207, and thus should be considered in the context of the standard as it stood at the time that defect was addressed. At that time there was some concern over the rewriting of id-expressions into member access expressions using *this (9.3.1p3), in particular in the context of trailing-return-type declarations (see issue 945).
If we compare the proposed resolution to defect 1207 to the eventual language in n3282 and subsequently in the standard, there is one significant difference to 9.3.1p3:
Defect 1207:
When an id-expression (5.1 [expr.prim]) that is not part of a class member access syntax (5.2.5 [expr.ref]) and not used to form a pointer to member (5.3.1 [expr.unary.op]) is used in the declaration of a member function of class X, if name lookup (3.4 [basic.lookup]) resolves the name...
n3282 and C++11:
When an id-expression (5.1 [expr.prim]) that is not part of a class member access syntax (5.2.5 [expr.ref]) and not used to form a pointer to member (5.3.1 [expr.unary.op]) is used in a member of class X in a context where this can be used (5.1.1 [expr.prim.general]), if name lookup (3.4 [basic.lookup]) resolves the name [...]
It is apparent that the proposed resolution to defect 1207 carried the belief that id-expressions (to a static member) within a static member functions would need to be transformed to *this member access expressions and thus would need access to the type and value category of this. By the time n3282 was written this had been resolved in favour of the qualified-id transformation (also 9.3.1p3) which does not require this, but the language in 5.1.1p3 remained vestigially.
I would recommend raising this issue on the C++ standards discussion newsgroup; it may be possible to get the vestigial language removed editorially.
Up until now I was under the impression that things like immutable and const were storage classes. In a recent video (at around 11:55) Walter Bright states that immutable is not a storage class, but rather it's a type constructor. In the official documentation, immutable, const, and among many other keywords, are listed as being storage classes:
StorageClass:
abstract
auto
const
deprecated
enum
extern
final
immutable
inout
shared
nothrow
override
pure
__gshared
Property
scope
static
synchronized
Is this list wrong? Some of it doesn't make sense(e.g., deprecated, override).
I know static and ref are storage classes, but what's the rest? And which one of the keywords in D are type constructors?
I would point out that there is a big difference between a grammar rule named StorageClass, and what is semantically a storage class in the language. The grammar rules have to do with parsing, not the semantic phase of compilation.
First off, TDPL, chapter 8, is explicitly about type qualifiers (for which Walter used the term type constructor). There are only 3 of them in D:
const
immutable
shared
All three of them are a part of the type that they modify. Such is not true with storage classes such as ref.
inout is what TDPL calls a "wildcard qualifier symbol," so it's a placeholder for a type qualifier rather than really being either a type qualifer or a storage class.
Now, as to what's a storage classes or not, I give two quotes from TDPL:
Each function parameter (base and exponent in the example above) has, in addition to its type, an optional storage class that decides the way that arguments are passed to the function when invoked.
(from pages 6 - 7)
Although static is not related to passing arguments to functions, discussing it here is appropriate because, just like ref, static applied to data is a storage class, meaning an indication about a detail regarding how data is stored.
(from page 137)
Also, there's this line with regards to storage classes in C which seems to be used quite a bit in explanations on storage classes in C found online:
A storage class defines the scope (visibility) and life time of variables and/or functions within a C Program.
A storage class has no effect on the type of a variable, just how it's stored. Unfortunately, I can't find an exact list of storage classes in D, and people are quite liberal with the term storage class, using it even when it doesn't apply. Pretty much any attribute applied to a type save for access modifiers seems to get called a storage class, depending on who's talking. However, there are a few which are beyond a doubt storage classes:
enum (when used as a manifest constant)
extern
lazy
out
ref
scope
static
lazy, out, and ref can be used to modify function parameters and indicate how they're passed, whereas enum and static are used to indicate how the variables are stored (which is nowhere in the case of enum, since manifest constants are copy-pasted everywhere that they're used rather than being actual variables). extern affects linkage.
in is a hybrid, since it's a synonym for scope const, and while scope is a storage class, const is a type qualifier.
The online documentation also refers to auto and synchronized as storage classes, though I don't know on what basis. auto is like inout in that it's a placeholder (in its case a placeholder for a type rather than a type qualifier) and therefore indicates nothing about how a type is stored, so I wouldn't have thought that it would be a storage class. synchronized doesn't modify variables but rather classes.
__gshared is probably a storage class as well, though it's a bit funny, since it does more or less what shared (which is a type qualifier) does, but it's not part of the type.
Beyond that, I don't know. The fact that synchronized is listed as a storage class implies that some of the others (such as final) might be, but (like synchronized) they have nothing to do with how variables are stored or linked. So, I don't know how they could be considered storage classes.
I'll ask on the newsgroup though and see if I can get a more definitive list.
EDIT: It seems that there is no definitive, official list of storage classes in D. The term is used for almost any attribute used on a variable declaration which doesn't affect its type (i.e. not a type qualifier). It seems that Walter and Andrei tend to make a big point about the type qualifiers to underline which attributes actually affect the type of a variable, but the term storage class hasn't been given anywhere near the same level of importance and ends up being used informally rather than per any rigorous definition.