I found the following code in a header file and the "BOOT" class is defined in another header file.
class BOOT* boot(void);
It looks like a declaration of a function, but it begins with class.
This is an elaborated type specifier:
Elaborated type specifiers may be used to refer to a previously-declared class name (class, struct, or union) or to a previously-declared enum name even if the name was hidden by a non-type declaration. They may also be used to declare new class names.
https://en.cppreference.com/w/cpp/language/elaborated_type_specifier
Taking from answers of Artefacto and dfrib because it brings it on point: It is equivalent to:
class BOOT;
BOOT* boot(void);
In your example it essentially does a forward declaration of the class BOOT if it is not known yet. See this example struct Data* Data; from the same page:
struct Node {
struct Node* Next; // OK: lookup of Node finds the injected-class-name
struct Data* Data; // OK: declares type Data at global scope
// and also declares the data member Data
friend class ::List; // error: cannot introduce a qualified name
enum Kind* kind; // error: cannot introduce an enum
};
Data* p; // OK: struct Data has been declared
It is the same as this:
class BOOT;
BOOT* boot(void);
So it's a pointer to class BOOT, but with a declaration of the class as well. The class need not be defined at this point.
What does “class classname* funcname(void) ”mean in C++?
It is a function declaration.
It looks like a declaration of a function, but it begins with "class".
class classname* is the return type of the function. class classname is an elaborated type specifier.
Different forms of forward declarations used to introduce class-name:s into its scope
In C++ you may declare a function type whose return type contains a class type that is defined elsewhere, as long as you either explicitly forward declare the class type prior to the function declaration:
class BOOT;
BOOT* boot();
but you may likewise place the forward declaration in-line in the function declaration:
class BOOT* boot();
This is one of the places where, possibly somewhat unexpectedly, forward declarations can be used. Another example is as in the template argument list for a type-template parameter:
template<typename T>
struct Identity { using type = T; };
using IdentityBoot = Identity<struct BOOT>;
// ^^^^^^^^^^^ also a forward declaration
// OK
BOOT* boot();
// OK
typename IdentityBoot::type* another_boot();
Elaborated type specifiers can be used to introduce names into its scope
Formally, it's an elaborated-type-specifier, governed by [dcl.type.elab],
elaborated-type-specifier:
class-key [...]
[...]
that is used to, as per [class]/1, make a class-name that is introduced into the scope where the elaborated-type-specifier is used [emphasis mine]:
A class is a type. Its name becomes a class-name ([class.name]) within its scope. [...]
Class-specifiers and elaborated-type-specifiers are used to make class-names.
Related
The following code doesn't compile:
struct X {
friend class Y;
Y* ptr;
};
The cppreference describes the situation as
... If the name of the class that is used in the friend declaration is
not yet declared, it is forward declared on the spot.
If the "spot" means where the friend relationship is declared, then it should be fine to declare the member Y* ptr. Why doesn't it compile? Where in the standard prohibits this?
This is a mistake on the site. It contradicts the standard, which says that friendship declaration is not a substitute for a forward declaration:
7.3.1.2.3 Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup or qualified lookup.
The part about the name not being visible to unqualified or qualified lookup essentially means that the name does not behave like a forward declaration.
In addition to the answer of #dasblinkenlight, a note in 3.3.2 Point of declaration lit. 10 explicitly says that a friend declaration does not introduce (and therefore not "forward declare") a class name:
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 ([namespace.memdef]).
One way to fix this code is to simply add class keyword:
struct X {
friend class Y;
class Y* ptr;
};
This will forward declare class Y at the global scope, if X is in the global scope.
Recently, I saw a strange C++ feature: injected class name.
class X { };
X x1;
class X::X x2; // class X::X is equal to X
class X::X::X x3; // ...and so on...
But I cannot figure out why this feature is necessary. Is there any practice that requires this feature?
And I heard this feature didn't exist in old C++. Then, when was it introduced? C++03? C++11?
The injected class name means that X is declared as a member of X, so that name lookup inside X always finds the current class, not another X that might be declared at the same enclosing scope, e.g.
void X() { }
class X {
public:
static X create() { return X(); }
};
Is the create() function creating a temporary X object or calling the function X? At namespace scope it would call the function, so the purpose of the injected-class-name is to ensure that within the body of X the name always finds the class itself (because name lookup starts in the class' own scope before looking in the enclosing scope).
It's also helpful inside class templates, where the injected class name can be used without a template argument list, e.g. using simply Foo instead of the full template-id Foo<blah, blah, blah>, so it's easy to refer to the current instantiation. See DR 176 for a change between C++98 and C++03 that clarified that.
The idea of the injected class name was present in C++98, but the terminology was new for C++03.
C++98 says:
A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself.
The second sentence was changed by DR 147 so C++03 says in [class]/2:
A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.
Even before C++98, the ARM has roughly equivalent wording that means the class' name can always be used in the class body to refer to the class itself:
The name of a class can be used as a class-name even within the member-list of the class specifier itself.
For example,
class link { link* next; };
The title is already the question.
More details: the standard enacts:
If the enum-key is followed by a nested-name-specifier, the enum-specifier shall refer to an enumeration that
was previously declared directly in the class or namespace to which the nested-name-specifier refers (i.e.,
neither inherited nor introduced by a using-declaration), and the enum-specifier shall appear in a namespace
enclosing the previous declaration.
at 7.2, paragraph 4.
For example, this prohibits to forward-declare an enum defined inside a class:
struct S{
enum foo{A, B};
};
now, S can be forward-declared, while S::foo not.
Question is about why. Is there a situation in which this rule can be a benefit? Why is it needed? Or, if you prefer: if the standard had not this rule, is there a situation in which the compiler would have a problem? Which one(s)?
At least, if forward-declare an enum was allowed, it would have created problems with template specializations like the one in the following example:
// somewhere in a .cpp
template<typename>
struct S;
enum S<int>::E;
// somewhere in a galaxy far, far away
template<typename>
struct S { enum class E {}; };
template<>
struct S<int> {};
How could the compiler know (and verify) that enum S<int>::E; is actually defined?
That said, even when you deal with namespaces you cannot do this:
struct X::A;
namespace X { struct A {}; }
But you can do this:
namespace X { struct A; }
namespace X { struct A {}; }
Using classes would result in a code like the following one:
struct A { enum E; };
struct A { enum E {} };
Anyway, this would violate the odr and it is not allowed.
Now, I'll try to give you my impression about the why.
If a forward-declaration of that type was allowed, you would have been allowed to give a partial definition of the containing class.
In other terms, consider this: enum S::E. This states firmly that S contains the enum class E, thus you are giving a clue about the definition of S. To speak not in standardese (that is far from being my natural language) you are partially defining S, thus the compiler should know that S has its definition somewhere plus it must have a definition for E too (either as part of the primary definition or as an out-of-class definition).
This would break the odr rules when the actual definition comes into view, so it cannot be allowed in any case, but as an exception of the basics rules of the language.
Moreover, this is a great source of headaches.
My two cents.
A scoped enum is declared with enum class (or enum struct, not with struct { enum …. That would be an unscoped enumeration, in the scope of a class.
struct S {
enum foo {A, B}; // Not a scoped enumeration.
};
A scoped enumeration can be forward-declared inside a class and defined outside:
struct S {
enum class foo;
};
enum class S::foo { A, B };
However, you cannot declare a class member outside the class, unless it was already declared and you're defining it. Allowing member declarations outside would go against the principle that a class { } definition declares all the class members, that C++ classes are "closed."
Put another way, the rules for declaring and defining member scoped enumerations are essentially the same as for member functions or member classes.
enum Enumeration; enum is not allowed to forward declare in header file.
enum class Enumeration; enum class is allowed to forward declare in header file.
I'm looking at this resource:
http://www.cplusplus.com/reference/vector/vector/
For example, the iterator member type on class vector.
Would a "member type" simply be implemented as a typedef or something similar in the vector class? It is not clear to me what "member type" actually means, and I've looked at a couple C++ textbooks, they don't even mention this phrase at all.
The C++ Standard does not use this phrase either. Instead, it would call it a nested type name (§9.9).
There are four ways to get one:
class C
{
public:
typedef int int_type; // as a nested typedef-name
using float_type = float; // C++11: typedef-name declared using 'using'
class inner_type { /*...*/ }; // as a nested class or struct
enum enum_type { one, two, three }; // nested enum (or 'enum class' in C++11)
};
Nested type names are defined in class scope, and in order to refer to them from outside that scope, name qualification is required:
int_type a1; // error, 'int_type' not known
C::int_type a2; // OK
C::enum_type a3 = C::one; // OK
Member type simply stands for a type that is a member(of that class). It could be a typedef as you say (in the case of vectorit is likely to be T*) or it could be nested class (or struct).
Member type may refer to 'nested class' or 'nested structure'.
It means class inside another class. If you want to refer text books then search for 'nested classes'.
I did a mistake in my program, I wrote
struct vector<int> v;
instead of
vector<int> v;
but it seems that the compiler doesn't care: http://codepad.org/TCPb8p2u
Why does it work? Is there some differencies with or without struct?
If you write class, it would also work.
class vector<int> v;
See this: http://www.ideone.com/EoJxk
This is actually old C style. The C++ Standard calls it elaborated-type-specifier in section §3.4.4.
The keyword struct (or class, enum) is sometimes used to remove ambiguities, or to make hidden names visible to the compiler. Consider the following example from the Standard itself (from section §9.1/2). Please notice that there exists a struct with name stat and with exactly same also exists a function:
struct stat {
// ...
};
stat gstat; // use plain stat to define variable
int stat(struct stat*); // redeclare stat as function
void f()
{
struct stat* ps; // struct prefix needed to name struct stat
// ...
stat(ps); //call stat()
// ...
}
§9.1/2 says,
A class definition introduces the
class name into the scope where it is
defined and hides any class, object,
function, or other declaration of that
name in an enclosing scope (3.3). If a
class name is declared in a scope
where an object, function, or
enumerator of the same name is also
declared, then when both declarations
are in scope, the class can be
referred to only using an
elaborated-type-specifier (3.4.4).
This is a feature of C++ that's used to resolve ambiguity between a variable and type with the same name. I believe they're called 'elaborate type specifiers.'
You can use a keyword to tell the compiler exactly what you mean, when there would normally be ambiguity.
Take this for example:
int x = 0;
class x { };
// Compiler error! Am I refering to the variable or class x?
x y;
// This is okay, I'm telling the compiler which x I'm referring to.
class x y;
This can also be used to specify enums and unions, not just structs and classes, though you can only have one user-defined type with the same name.
The others have already explained it that what you uses is called elaborated type specifier, which can be used for name unhiding and ambiguity resolution.
However, what also works here is one curious feature of C++ language, which states that class-key (i.e. class or struct keyword) used in class declaration is not required to agree with the class-key used in the elaborated type specifier. E.g. you can declare your class with class keyword and then later refer to it with struct keyword (and vice versa). There's no error in it
class S {};
int main() {
struct S s; // OK, 's' has type `S` (i.e. `class S`)
}
Standard std::vector template class is declared with keyword class, but there's no error in referring to it as struct std::vector, which is what you did in your example.
And no, it makes no difference whether in your declaration of v you use class, struct or nothing at all.