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'.
Related
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.
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.
So as I understand it, when I see double colons(abc::xyz) used the thing on the left is a namespace and the thing on the right can be a function or variable of some sort that is defined in that namespace. ex. namespace::bar, namespace::foo()
Now, can the thing on the left be a class? ex. class::bar, class::foo()
If so, does anyone have any info on this. I can find lots of info of scope resolution pertaining to namespaces but not when it comes to classes.
In my situation I am going through a rather large project of code that is from another individual.
The code usage that I am trying to understand is that I have the following line of code...
multi_img::ptr input = imginput::ImgInput(config.input).execute();
On the right the imginput::ImgInput() can be found because there is a namespace imginput that I can find. But on the left, the multi_img::ptr, there is no multi_img namespace in the project. There is a multi_img class that contains the following line...
typedef boost::shared_ptr<multi_img> ptr;
I believe this is what multi_img::ptr means but can not find any documentation to back up my assumption.
Now, can the thing on the left be a class?
Yes it can, and to justify consider the following example:
#include <iostream>
class foo {
public:
void fun() const { std::cout << "foo:fun()" << std::endl; }
};
int main() {
foo f;
f.foo::fun();
return 0;
}
DEMO
Every class member lies in the scope of its class.
Edit after #Cheersandhth.-Alf constructive comment:
Thus, you can access a member through an object with either the classical way (e.g., f.fun()) in which case you'll have a virtual call or you call it like in the example (i.e., f.foo::fun()) in which case you explicitly disambiguate the scope of member function at compile time.
Yes, you can have a class name on the left of ::. It is used to denote a member of that class. The multi_img class has a member called ptr. As you have shown, that member is a typedef. That is, the type multi_img::ptr is a synonym of boost::shared_ptr<multi_img>.
Note that :: is used to access static members and nested types, since these only require the name of the class and not a particular object that of that class type. We use . and -> to access non-static data members of a particular object.
Usually the classname::member notation is used to
Access static members.
E.g. Blah::uuid.
Prevent virtual call.
E.g. in Blah::foo, a call like Base::foo().
Disambiguate.
E.g. with two bases A and B, both of which provides a foo, a call like B::foo().
Some older libraries use classes instead of namespaces. I vaguely recall an XML library and a GUI library. Not sure which.
Personally I do the class-as-faux-namespace for enumeration types, e.g.
struct Weekdays
: Non_instantiable
{
enum Enum { wednesday, friday, saturday };
};
used like
auto foo() -> Weekdays::Enum { return Weekdays::friday; }
even after C++11 started supported enum class.
Sometimed it is difficult to know whether the nested name specifier denotes a namespace or a class because the syntax is the same. Moreother the same name can denote either a namespace or a class depending on the declaration region where the name is used. For example
namespace A
{
struct A
{
static int a;
static int b;
static int c;
};
int A::a = 5;
}
int A::A::b = 10;
int A::A::c = a;
The most appropriate documentation is the C++ Standard. You may download a working draft of the Standard from the ISO-IEC site
As for the typedef that defines a type
typedef boost::shared_ptr<multi_img> ptr;
then it seems that it is defined in the class definition of multi_img. So if the name is used outside the class scope it shall be qualified
multi_img::ptr input = imginput::ImgInput(config.input).execute();
namespace O
{
class A{};
class A; // ok
typedef A K; // ok
struct A; // ok(C++11): A is a class but for references and pointer it have the same meaning
class K; // (1) error: K is a typedef (of a class...)
}
namespace U
{
typedef O::A A;
class A; // (2) error: A is a typedef (of a class...)
}
What is the reason(s) standard C++ don't allow these cases (1 & 2) to compile?
You are confused or your example doesn't show what you're asking about. In your example code you are not trying to "forward declare a typedef" (such as thing isn't possible or useful, see below) you are trying to redeclare an existing typedef-name (i.e. an alias for one type) as a completely different type.
You've already said K is a typedef for A, then you say it's a class K. Make your mind up. It's can't be both class A and class K. Both (1) and (2) fail for that same reason.
Going through these lines of the example:
class A; // ok
typedef A K; // ok
Right so far.
struct A; // ok(C++11): A is a class but for references and pointer it have the same meaning
I don't know why you've said "C++11" here, this is OK in C++03 too. Classes and structs are the same kind of thing in C++. They are both "object types" and both "class types". For a forward declaration the class-key (i.e. struct or class) is interchangeable.
class K; // (1) error: K is a typedef (of a class...)
K has been declared as a typedef for class A, the name can't be reused for declaring a new type in the same scope.
[Aside: C does allow the following, because struct names and typedef names are in separate namespaces:
struct A { };
typedef struct A K; // N.B. need "struct A" not just "A"
struct K { };
But now there are two different types called struct K and K, which are unrelated. Doing this would be confusing and pretty dumb.]
But from your comments maybe that's not what you're actually trying to do anyway.
Based on your comments maybe your broken examples are misleading and what you really want to do is:
typedef class A K; // forward declare A as class and declare K as typedef for it
This declares a typedef, for a type which is not defined yet.
It would be useless to forward-declare a typedef, you couldn't do anything with it because you wouldn't know what kind of type it was a typedef for, and there is very little you can do in C++ without knowing something about a type. Without knowing if it's an object type, reference type or function type all you can realistically do is declare another typedef for it!
Consider:
typedef K; // declares K to be a typedef
K* f(); // function returning pointer to K
void g(K*); // function taking pointer to K
I think you're saying you want that to be valid, so do you expect this to work?
K* k = f();
g(k);
That should work, right? You don't need to know the type of K because you only pass around pointers to it, right? Wrong. What if you later define K like this:
typedef int& K;
Now f has the signature int&* f() which is invalid. You have to know what a typedef is a typedef for, so its declaration has to say what it is not just forward-declare it as a name.
Let me just tackle the first error:
You create class A: at this point, the name 'A' is assigned to that class; no other entities in this scope can be called 'A'.
Then you typedef so that K now refers to A, so no other entities in this scope can be called 'K'.
Then you try to forward declare K. Forward declaration on its own is fine, but the name K is already taken by your typedef. It has little to do with A at this point. You wouldn't be able to forward declare A either, both names are already taken by your previous uses.
What are you trying to do anyways?
I can not found this thing in C++2003 standard. But C compiler doesn't allow such thing because typedef construction define new type, and then you try to define new type one more time via class A.
In principle usage of "forward declaration class" was allowed for two use cases:
typedef-names
pointer to the structure
This both operations doesn't need info about sizeof type and it's memory layout.
Also in list above there is no "references" because there is no reference s in C language.
See also: (Samuel P. Harbison, Guy L.Steele] C A Reference, page 151.
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.