Type of `this` in static member function? - c++

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.

Related

What is the meaning of the last sentence in [basic.lookup]/1?

[basic.lookup]/1:
The name lookup rules apply uniformly to all names (including typedef-names (10.1.3), namespace-names
(10.3), and class-names (12.1)) wherever the grammar allows such names in the context discussed by a
particular rule. Name lookup associates the use of a name with a set of declarations (6.1) of that name. The
declarations found by name lookup shall either all declare the same entity or shall all declare functions; in the
latter case, the declarations are said to form a set of overloaded functions (16.1). Overload resolution (16.3)
takes place after name lookup has succeeded. The access rules (Clause 14) are considered only once name
lookup and function overload resolution (if applicable) have succeeded. Only after name lookup, function
overload resolution (if applicable) and access checking have succeeded are the attributes introduced by the
name’s declaration used further in expression processing (Clause 8).
What are those attributes introduced by the names´s declaration?
This sentence is visible in the N1638 - C++ Working Draft from April 2004, so it doesn't refer specifically to attributes of the form [[...]], which were introduced to the standard by N2761 - Towards support for attributes in C++
(Revision 6) in 2008.
[basic.lookup]/1
Only after name lookup, function overload resolution (if applicable) and access checking have succeeded are the attributes introduced by the name’s declaration used further in expression processing (clause 5).
Also [basic.def]/1
A declaration (clause 7) introduces names into a translation unit or redeclares names introduced by previous declarations. A declaration specifies the interpretation and attributes of these names.
From the above, and looking at the five other occurrences of 'attribute' in that paper, it appears to me that 'attribute' just means "information about the name". So in this case, things like extern, friend, the body of a function definition, and anything else you can say about a name in a declaration, that wasn't part of determining the interpretation of a name.
Since C++11 this would also include "generalised attributes" in the form [[..]]. There's a hint here, N2761 didn't introduce 'attributes', it just gave us a generalised syntax for them.
Function parameters, conversely, would not be 'attributes' in this sense, as the interpretation of the function name involves the parameters as part of overload resolution. The return type would be an attribute, since we don't look at it until we know what the name means, and which overload we've chosen.
In a slightly-more-standardese sense, I think you can say that the 'specifiers' are attributes, while the 'declarators' specify the interpretation of a name.
Pratically, I would say (without checking for a more-specific rule) that this is the rule that requires that deleted functions survive all the way through the lookup and name resolution process, and then fail the compilation.
Otherwise, a crafty compiler author might want to save their users some grief by eliminating deleted functions earlier, on the grounds that you can't call a deleted function, so why bother including it in the overload set?

Deprecating static class members in C++11

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.

How are unqualified-ids other than identifier categorized in terms of lvalue and rvalue?

It seems that the standard does not explicitly talk about the expression categories of some unqualified-ids. On the other hand, an identifier, which is one of unqualified-ids, is categorized as follows:
The result is an lvalue if the entity is a function, variable, or data member and a prvalue otherwise.
Then, what about other unqualified-ids—operator-function-id, conversion-function-id, literal-operator-id, ~class-name, ~decltype-specifier, template-id?
This has been acknowledged as Core Working Group issue 536 which has been submitted almost 10 years ago. So probably it hasn't been deemed important enough to be fixed.
More importantly, some kinds of id-expressions are not described by
5.1.1 [expr.prim.general]. The structure of this section is that the result, type, and lvalue-ness are specified for each of the cases it
covers [...]
This treatment leaves unspecified all the non-identifier
unqualified-ids (operator-function-id, conversion-function-id, and
template-id) [...]
-- CWG 536
From the behaviour of various compilers, we can assume the intention is that all of those expressions follow the rule for identifiers:
The type of the expression is the type of the identifier. The result is the entity denoted by the identifier. The result is an lvalue if the entity is a function, variable, or data member and a prvalue otherwise.
-- post-N4296 [expr.prim.general]p13
By the way: all of those expressions but template-ids can only refer to functions. Template-ids can refer to variables as well. Both template-ids and ordinary identifiers can refer to classes and enums, which confused me slightly (can there be expressions such as int? are they prvalues?)

Access C++14 lambda captures like struct members

AFAIK, C++11/14 does not allow in-place definition of a new return type while defining a lambda. However, it seems a C++14 lambda capture expression essentially creates an anonymous type with one or more "members" and an operator (). So, why is that the compiler does not allow access to the captured members from outside the lambda. My feeble mind cannot handle the complexities of C++ but does it sound like a reasonable language extension to you? Here is an example.
vector<string> words = { "Stack", "Overflow" };
auto l = [w = words](){}; // almost like a C# anonymous type
cout << l.w[0]; // does not work.
The status quo
This was discussed when lambda init-captures were added to the language. The current working draft of the standard (N3797) says (in [expr.prim.lambda]p11):
For every init-capture a non-static data member named by the identifier of the init-capture is declared in the closure type.
The standard does not specify the access of that member, making it unclear whether this is valid:
auto x = [n(0)] {};
int k = x.n; // ok?
This and some other specification problems with init-captures led to national body comment GB3 on the standard draft, which is handled by the C++ core working group as core issue 1760. In discussion of that issue, the core working group decided that the lambda's init-captures should not be accessible members of the closure object.
The resolution for issue 1760 (which is approved by CWG but not yet by the full committee) changes the specification to instead say:
An init-capture behaves as if it declares and explicitly captures a variable of the form “auto init-capture ;” whose declarative region is the lambda-expression's compound-statement [...]
This new wording makes it clear that the init-capture does not add a nameable member of the closure object, and it instead acts like any other lambda capture.
As a language extension
Making init-captures be accessible members of the closure type is certainly possible (and my initial implementation of init-captures in clang did that, before I implemented the resolution of issue 1760). It also seems like a useful feature, but it would also allow violation of the encapsulation of lambda-expressions in the common case where the init-captures should not be visible.
If I'm understanding this right, you want to be able to access a variable that is captured within a lambda. But according to the top answer on Get captured variables from lambda?, it's not possible.
It's not possible by design
5.1.2 [expr.prim.lambda]
15 [...] For each entity captured by copy, an unnamed non-static data member is declared in the closure type. The declaration order of these members is unspecified. [...]
16 [...] It is unspecified whether additional unnamed non-static data members are
declared in the closure type for entities captured by reference.
Captured variables are unnamed (or at least have names that are
unspeakable by mortals) and their declaration order is deliberately
unspecified. By-reference captures may not even exist in the closure
type.
Bold emphasis mine.

Static Constant Class Members

Consider the following snippet:
struct Foo
{
static const T value = 123; //Where T is some POD-type
};
const T Foo::value; //Is this required?
In this case, does the standard require us to explicitly declare value in a translation unit? It seems I have conflicting information; boost and things like numeric_limits from the STL seem to do this sort of thing just like in my snippet.
OTOH, I remember reading somewhere (albeit a long long time ago) that you're still required to provide a declaration in a translation unit.
If this is the case, what about template specialization? Will each specialization require a declaration?
I'd appreciate your comments as to what the "right way" is.
You have to provide a definition in a translation unit too, in case you use the value variable. That means, if for example you read its value.
The important thing is that the compiler is not required to give a warning or error if you violate that rule. The Standard says "no diagnostic required" for a violation.
In the next C++ Standard version, the rule changed. A variable is not used when it is used as a constant expression. Simply reading value above where the variable is initialized directly in the class means that still no definition is required then.
See the definition of use in section 3.2 One Definition Rule of the Standard and requirement for a definition for static data-members in 9.4.2, paragraph 4 and 5 (in the C++98 Standard. Appears in paragraph 3 and 4 in the n2800 draft of the next Standard).
Correction: The rule already changed for c++03: If the variable appears where a integral constant expression is required, no definition is needed (quoting from an unofficial revisions list for the 2003 update), see resolution for this language defect report:
An expression is potentially evaluated unless it appears where an integral constant expression is required (see 5.19), is the operand of the sizeof operator (5.3.3), or is the operand of the typeid operator and the expression does not designate an lvalue of polymorphic class type (5.2.8)...
Note that even then, many uses are in cases where an integral constant is not required. Cases where one is, is in array dimensions or in template metaprogramming. So strictly speaking (see this report), only the c++1x solution provides really guarantee that in obvious cases also like "s == string::npos" where an integral constant is not required the definition of the static member is not needed, because the next Standard has a different, better wording of 3.2. This is however quite theoretical stuff, since most (all?) compiler don't moan anyway. Thanks for the guy in the comment section for telling me.
To add on to what litb said, from my copy of n2798:
9.4.2
[...]
2 The declaration of a static data member in its class definition is not a definition and
may be of an incomplete type other than cv-qualified void. The definition for a static
data member shall appear in a namespace scope enclosing the member’s class definition. In
the definition at namespace scope, the name of the static data member shall be qualified
by its class name using the :: operator.
You don't have to provide a definition for static integral constant members if you don't use them in some way that requires them to be stored in memory somewhere (e.g. take the address of such a member). See Stroustrup's The C++ Programming Language, section 10.4.6.2.
Edit:
Oops, I just re-read the question, and the question was for some type T. In general you would need to provide a definition, I agree. But if you used something from the int family, you wouldn't necessarily have to (with the caveat above).