Ambiguity Resolution - c++

void S(){}
struct S{};
int main(){
S();
}
In the code above, the expression 'S()' in main is treated as a function call expression rather than an attempt to create a temporary of type 'S'.
Which portion of the C++ Standard talks about the resolution of such an expression in favour of a function declaration? For some reason I am unable to locate it.

Section 3.3.7/2
A class name (9.1) or enumeration name (7.2) can be hidden by the name of an object, function, or enumerator declared in the same scope. If a class or enumeration name and an object, function, or enumerator are
declared in the same scope (in any order) with the same name, the class or enumeration name is hidden
wherever the object, function, or enumerator name is visible.
Then you need to use elaborated type specifier in such cases
3.4.4/1 Elaborated type specifiers
An elaborated-type-specifier may be used to refer to a previously declared class-name or enum-name even
though the name has been hidden by a non-type declaration (3.3.7). The class-name or enum-name in the
elaborated-type-specifier may either be a simple identifer or be a qualified-id.

It can be resolved either by using the scope resolution operator(::) or by using virtual keyword(when we are dealing with either multiple or hybrid inheritance.

Related

What name spaces are there and what are the rules?

Note: this question is about name space, not namespace.
The C++ standard has some references to name space, but I don't see the definition of this. The standards says that labels and macros are in different name spaces. All the other references to name space are in the C/C++ compatibility section, like this (current draft):
This is one of the few incompatibilities between C and C++ that can be attributed to the new C++ name space definition where a name can be declared as a type and as a non-type in a single scope causing the non-type name to hide the type name and requiring that the keywords class, struct, union or enum be used to refer to the type name. This new name space definition provides important notational conveniences to C++ programmers and helps making the use of the user-defined types as similar as possible to the use of fundamental types.
What is this new name space definition? Where can I find it in the standard? What are the exact rules? The rules seem to be more complicated, than "non-types hide types". Like, this doesn't compile:
typedef int Foo; // Foo is a type
void Foo(); // not a type, but compile error, instead of hiding
But this does:
struct Foo { }; // Foo is a type as well
void Foo(); // This hides the type Foo. "struct Foo" refers to the type
And this doesn't compile either:
struct Foo { }; // Type
namespace Foo { } // Non-type, but compiler error instead of hiding
The name space term may be more well-established in the ISO C Standard; citing ISO C11:
6.2.3 Name spaces of identifiers
If more than one declaration of a particular identifier is visible at any point in a translation unit, the syntactic context disambiguates uses that refer to different entities. Thus, there are separate name spaces for various categories of identifiers, as follows:
label names (disambiguated by the syntax of the label declaration and use);
the tags of structures, unions, and enumerations (disambiguated by following any32) of the keywords struct, union, or enum);
the members of structures or unions; each structure or union has a separate name space for its members (disambiguated by the type of the expression used to access the member via the . or -> operator);
all other identifiers, called ordinary identifiers (declared in ordinary declarators or as enumeration constants).
The new name space definition of C++ is, however, not in any way recent in time, and has been described in [diff.class]/1 in its current form ever since the ISO C++ Standard's introduction in '98. It's only ever mentioned in any length in the contexts for which it differs from ISO C, as per [diff.class]/1 which is quoted by the OP.
Afaics we need to resort to ISO C11/6.2.3 and combine it with [diff.class]/1 of the ISO C++ Standard for a cohesive and complete description of the (new) name space definition of C++, less we scourge the ISO C++ Standard for e.g. [basic.scope.hiding], [class.name]/2, [stmt.label]/1, [cpp.replace]/8 and so on to see how and where it applies.
[class.name]/2
A class declaration introduces the class name into the scope where it is declared and hides any class, variable, function, or other declaration of that name in an enclosing scope. [...]
[stmt.label]/1
[...] Labels have their own name space and do not interfere with other identifiers [...]
[cpp.replace]/1
[...] There is one name space for macro names. [...]
In C (6.2.3 Name spaces of identifiers) the notion of name spaces is defined the following way.
1 If more than one declaration of a particular identifier is visible
at any point in a translation unit, the syntactic context
disambiguates uses that refer to different entities. Thus, there are
separate name spaces for various categories of identifiers, as
follows:
— label names (disambiguated by the syntax of the label declaration
and use);
— the tags of structures, unions, and enumerations (disambiguated by
following any32) of the keywords struct, union, or enum);
— the members of structures or unions; each structure or union has a
separate name space for its members (disambiguated by the type of the
expression used to access the member via the . or -> operator);
— all other identifiers, called ordinary identifiers (declared in
ordinary declarators or as enumeration constants).
So for example a structure tag name can coincide with a function name because they belong to different name spaces. When you specify a structure with a structure tag name when you have to use the keyword struct. So for example these declarations do not conflict.
struct s
{
int s;
};
void s( void );
struct s s1;
In this code snippet the tag name s of the structure does not conflict with the function name s because the tag name shall be specified with the keyword struct.
In C++ you are allowed to use structure tag names without the keyword struct.
For example
struct s
{
int s;
};
s s;
is a correct code. In this declaration
s s;
the name of the declared identifier s hides the structure name. SO if then you will write for example
s s1;
then the compiler will issue an error because in this statement s is considered as the name of the identifier declared above. To resolve the ambiguity you need to use the keyword struct
struct s
{
int s;
};
s s;
struct s s1;
This is described in the following quote from the C++ 20 Standard (6.3.1 Declarative regions and scopes)
4 Given a set of declarations in a single declarative region, each of
which specifies the same unqualified name,
(4.1) — they shall all refer to the same entity, or all refer to
functions and function templates; or
(4.2) — exactly one declaration shall declare a class name or
enumeration name that is not a typedef name and the other declarations
shall all refer to the same variable, non-static data member, or
enumerator, or all refer to functions and function templates; in this
case the class name or enumeration name is hidden (6.3.10). [ Note: A
namespace name or a class template name must be unique in its
declarative region (10.3.2, Clause 17). — end note ]
As you can see from the quote a namespace name must be unique in its declarative region. So these declarations
struct Foo { };
namespace Foo { }
are incorrect.

Name lookup in template base: why do we add this->

Consider the following:
struct Base {
void foo();
};
template <class T>
struct Derived : Base {
void bar() {
this->foo();
}
};
Typically, we explain that this-> makes foo() a dependent name, so its lookup is posponed to the second phase, i.e. to the template instantiation point.
But the second phase lookup invokes only ADL, which does not consider member functions, does it?
I'd appreciate any pointer to the Standard paragraph that explains why the above code compiles.
But the second phase lookup invokes only ADL, which does not consider member functions, does it?
It does not. However ADL adds to the lookup set, it does not comprise all of it. Also, the idea you are paraphrasing here applies to a postfix-expression in postfix-expression(args), when said postfix-expression is an unqualified-id.
[temp.dep]
1 ... In an expression of the form:
postfix-expression ( expression-listopt )
where the postfix-expression is an unqualified-id, the unqualified-id
denotes a dependent name if
[... specific conditions ...]
If an operand of an operator is a type-dependent expression, the
operator also denotes a dependent name. Such names are unbound and are
looked up at the point of the template instantiation ([temp.point]) in
both the context of the template definition and the context of the
point of instantiation.
So if you had there foo() instead, lookup would not consider members, and would instead try only free functions, both at the point of definition and instantiation (where ADL can add to the lookup set, assuming we had a dependent expression).
But for this->foo (I omitted the call intentionally, to discuss the postfix-expression), we have class member access. And here other paragraphs apply:
[temp.dep.type]
5 A name is a member of the current instantiation if it is
[...]
An id-expression denoting the member in a class member access expression for which the type of the object expression is the current instantiation, and the id-expression, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof. [ Note: If no such member is found, and the current instantiation has any dependent base classes, then the id-expression is a member of an unknown specialization; see below.  — end note ]
6 A name is a member of an unknown specialization if it is
[...]
An id-expression denoting the member in a class member access expression in which either
the type of the object expression is the current instantiation, the current instantiation has at least one dependent base class, and name
lookup of the id-expression does not find a member of a class that is
the current instantiation or a non-dependent base class thereof; or
7 Similarly, if the id-expression in a class member access expression for which the type of the object expression is the current instantiation does not refer to a member of the current instantiation or a member of an unknown specialization, the program is ill-formed even if the template containing the member access expression is not instantiated; no diagnostic required.
These bullets tell us what lookup to perform when this->foo is encountered. It looks up members only. In our case, we have a non-dependent base class in the current instantiation, so that's where the member is to be found, unambiguously.
Having found the member function, the postfix-expression this->foo denotes a callable, and that is how the function call is resolved.
The phrase “two-phase lookup” is widely misunderstood, even among experts. C++17 said both
Such names are unbound and are looked up at the point of the template instantiation (17.6.4.1) in both the context of the template definition and the context of the point of instantiation.
(in [temp.dep]/1) and
In resolving dependent names, names from the following sources are considered:
— Declarations that are visible at the point of definition of the template.
— Declarations from namespaces associated with the types of the function arguments both from the
instantiation context (17.6.4.1) and from the definition context.
(in [temp.dep.res]/1), each of which seems to suggest that these are the two phases. However, a better way of interpreting this (unofficial) phrase is that lookup is done
from the template definition: for non-dependent names
during instantiation: from the definition but also, via ADL only, from the instantiation context
The former can be done when parsing the template definition, but no diagnostic is required for uninstantiable templates ([temp.res]/8). Note that the latter includes more than ADL.
The relevant wording has been clarified recently; it now merely says
[Note: For the part of the lookup using associated namespaces ([basic.lookup.argdep]), function declarations found in the template instantiation context are found by this lookup, as described in [basic.lookup.argdep]. — end note]
as a reminder of the difference in the second phase. Nonetheless, it confusingly uses dependent name only to refer to unqualified dependent names/operators ([temp.dep]/2). Names like Derived::foo (from the this->) are clearly dependent; as qualified names, they’re not subject to ADL, but they are still looked up during instantiation—which allows results from a dependent base to be found. (Your example has a non-dependent base, but that’s available then too.)

Return alias identificator instead of type in typeid(SOME_TYPE).name()

In the following example
template <typename T>
void foo() {
const char* name = typeid(T).name();
std::cout << name;
}
the variable 'name' will be initialized by type 'T' name. It is very convinient if we need to print this template type name. But, if we have the alias:
using shortTypeName = std::smth::smth_else::smth_more;
in the result of the call
foo<shortTypeName>();
will be printed 'std::smth::smth_else::smth_more'. And I need to print exactly the alias name, but not the type it is defined. Can somebody give an advice, how I can do this?
... alias identificator ...
There's no such thing, at least not after compilation. It's just syntactic sugar and doesn't exist in any sense in the final executable.
The only way to grab the local name of a type (as opposed to the implementation-defined and probably-mangled typeid name) is with a stringize/stringify macro.
For future reference, this should eventually be possible when the Reflection TS lands - but I don't yet know whether to expect that to look like reflexpr(T).get_name(), or std::meta::name_of(^T), or something else again.
Can somebody give an advice, how I can do this?
The language does not support a mechanism to do this.
What you have is simply a type alias.
From http://en.cppreference.com/w/cpp/language/type_alias:
A type alias declaration introduces a name which can be used as a synonym for the type denoted by type-id. It does not introduce a new type and it cannot change the meaning of an existing type name.
You can't. Because a type alias is transparent: It is just a synonym for a new type, not a new type. As an implementation detail it doesn't even get mangled in the type system because it's not a type.
§7.1.3 The typedef specifier [dcl.typedef]
[...] A name declared with the typedef specifier becomes a typedef-name . Within the scope of its declaration, a typedef-name is
syntactically equivalent to a keyword and names the type associated
with the identifier in the way described in Clause 8. A typedef-name
is thus a synonym for another type. A typedef-name does not
introduce a new type the way a class declaration (9.1) or enum
declaration does.
A typedef-name can also be introduced by an alias-declaration . The identifier following the using keyword becomes a typedef-name and the
optional attribute-specifier-seq following the identifier appertains
to that typedef-name . It has the same semantics as if it were
introduced by the typedef specifier. In particular, it does not
define a new type and it shall not appear in the type-id .
typeid(T).name(); is pretty much useless anyway. Until we have proper introspection in C++ you have to resort to hacks to get what you want (macros, intrusive techniques or external code generator tools).

Inconsistent specialization of tuple_size

When explicitly specializing both tuple_size and tuple_element for some template, I realized that §14.5.1/4, which reads
In a redeclaration, partial specialization, explicit specialization or
explicit instantiation of a class template, the class-key shall agree
in kind with the original class template declaration (7.1.6.3).
is seemingly violated by the standard itself:
Am I missing something here (e.g. the standard specifies that class-keys are "exposition only" and shall agree within the actual implementation)?
Bo Persson's now-deleted answer got it right. The paragraph ([temp.class]/p4) you cite refers to §7.1.6.3 [dcl.type.elab] for the definition of "agree in kind", which in turn says (p3, emphasis mine)
The class-key or enum keyword present in the
elaborated-type-specifier shall agree in kind with the declaration to which the name in the elaborated-type-specifier refers. This rule
also applies to the form of
elaborated-type-specifier that declares a class-name or friend class since it can be construed as referring to the definition of the
class. Thus, in any elaborated-type-specifier, the enum keyword
shall be used to refer to an enumeration (7.2), the union
class-key shall be used to refer to a union (Clause 9), and either the class or struct class-key shall be used to refer to a class
(Clause 9) declared using the class or struct class-key.
The code is valid, if inconsistent.
This looks like an editorial defect to me. Try opening an issue here:
https://github.com/cplusplus/draft/issues
If you're adventurous, try resolving it with a pull request. :-)

Use of extern in block scope

clang, gcc and VS2013 all complain about redefinition of w in main(), but I couldn't find in the Standard anything disallowing this.
namespace N {
extern int j;
int j;
}
int main()
{
extern int w;
int w;
}
These paragraphs say something about the use of an extern declaration in block scope, but they don't seem to justify the error message:
§3.3.1/4
Given a set of declarations in a single declarative region, ...
[ Note: These restrictions apply to the declarative region into which
a name is introduced, which is not necessarily the same as the region
in which the declaration occurs. In particular,
elaborated-type-specifiers (7.1.6.3) and friend declarations (11.3)
may introduce a (possibly not visible) name into an enclosing
namespace; these restrictions apply to that region. Local extern
declarations (3.5) may introduce a name into the declarative region
where the declaration appears and also introduce a (possibly not
visible) name into an enclosing namespace; these restrictions apply to
both regions. —end note ]
§3.3.2/10
[ Note: Friend declarations refer to functions or classes that are
members of the nearest enclosing namespace, but they do not introduce
new names into that namespace (7.3.1.2). Function declarations at
block scope and variable declarations with the extern specifier at
block scope refer to declarations that are members of an enclosing
namespace, but they do not introduce new names into that scope. —end
note ]
I believe this is mostly covered by §3.5/6.
In particular:
The name of a function declared in block scope and the name of a variable declared by a block scope extern declaration have linkage. If there is a visible declaration of an entity with linkage having the same name and type, ignoring entities declared outside the innermost enclosing namespace scope, the block scope declaration declares that same entity and receives the linkage of the previous declaration. If there is more than one such matching entity, the program is ill-formed. Otherwise, if no matching entity is found, the block scope entity
receives external linkage.
So, the extern int w; declares a w that has linkage (external linkage, in this case, since no matching entity is visible at that point).
Then you attempt to define a local w which has no linkage (by §3.5/8).
That gives two declarations of the same name at the same scope, but with different linkages. That's prohibited by §3.3.1/4:
Given a set of declarations in a single declarative region, each of which specifies the same unqualified name,
they shall all refer to the same entity, or all refer to functions and function templates; or
exactly one declaration shall declare a class name or enumeration name that is not a typedef name
and the other declarations shall all refer to the same variable or enumerator, or all refer to functions and function templates; in this case the class name or enumeration name is hidden (3.3.10).
Neither refers to a function, function template, class name, or enumeration name, so none of these "escape clauses" applies. The two declarations must refer to the same entity, which must have both external linkage and no linkage. Since that's impossible, the code is ill-formed.
Here is my interpretation: In §3.3.1/3 the standard says:
The names declared by a declaration are introduced into the scope in which the declaration occurs, except that the presence of a friend specifier (11.3), certain uses of the elaborated-type-specifier (7.1.6.3), and using-directives (7.3.4) alter this general behavior.
As extern declarations are not listed as exception, the name is introduced in the block scope, which is why you get the error when you try to redeclare it.
The paragraph you quoted says
but they do not introduce new names into that scope.
which is a bit ambiguous, as both block scope and namespace scope are mentioned. The standard would contradict itself if it referred to block scope, so I assume that namespace scope is meant.