the basic_string class has npos which declared as static const.
Why it declares as static const since C++11, why not simple as:
class basic_string{
................................
enum: size_type { npos = static_cast<size_type>(-1) };
.........................>
};
???
which is good, static const or enum ?
There is a good reason not to do that, the enumeration creates a new type which will at least cause changes when resolving overloads or instantiating templates.
That said, I believe that you can actually declare and define class-static constants in the class definition, or is there some exception to that rule when the class is a template?
The two solutions are pretty much the same. The so called enum hack was born because of compilers which didn't support for in class initialization, mostly. The differences are: you cannot take the address of the enum "variable"; the static const approach is type-safe. Now, in C++11 enum classes are indeed type safe (except you stick to enums).
Basically, then, the only difference is in the "address of" issue. But, when you define an enum class you are defining a type; you might well find it to be bad looking to define a type when what you need is a constant.
Related
In c++, it's possible to define const static data members from within the class definition without defining it at namespace-scope. Doing so is valid so long as the constant is not ODR-used; this practice effectively does not provide a storage-backing in the translation-unit. For example:
#include <cstddef> // std::size_t
class my_string
{
public:
static const auto npos = static_cast<std::size_t>(-1);
};
I like to follow almost-always-auto guidelines where possible to achieve a consistent left-to-right readability while also keeping the typing generic. However, this is at odds with the few cases where you may actually want that symbol to be possibly ODR used. What I would like to do is:
#include "my_string.hpp"
const auto my_string::npos; // error!
However, this fails even under c++20 due to the type not being specified -- despite the fact that decltype(my_string::npos) is already known by this point. Ideally, I'd like the namespace-definition to not necessitate a change if ever the constant's type changes.
My question is: Is there any way to achieve a simple left-to-right syntax in such a scenario?
The only two ways I can think of to solve this are to either not specify the namespace-definition using c++17's inline variables, or to name the type by using decltype(my_string::npos) (which, though ugly, does work).
despite the fact that decltype(my_string::npos) is already known by this point
Well.. so just use it!
#include <cstddef> // std::size_t
class my_string {
public:
static const auto npos = static_cast<std::size_t>(-1);
};
const decltype(my_string::npos) my_string::npos; // all fine!
I know that ios_base has a declaration of states for streams like
ios_base::goodbit(error state)
ios_base::ate(file open mode state)
and many more.
What I'm interested in knowing is the definition of these member functions of ios_base
Are they a simple class or a class template? How are they implemented? Which one is there parent class(if any)?
Are they a simple class or a class template?
They are actually static constexpr declarations nested in the std::ios_base class (as from the reference documentation):
How are they implemented? Which one is there parent class(if any)?
As mentioned there, it's compiler implementation specific. Usually these are simple values without usage of a parent class.
They are not "member functions", they are just some constants.
As you can find in standard library headers, goodbit is a constant with type iostate, and ate is a constant with type openmode.
i.e. libc++ defines them in header "ios":
typedef unsigned int iostate;
static const iostate goodbit = 0x0;
...
typedef unsigned int openmode;
static const openmode ate = 0x02;
Technically speaking they are BitmaskType constexpr. Defined in ios_base namespace.
Bitmask type is defined in standard (this is c++14 working draft).
17.5.2.1.3 Bitmask types [bitmask.types]
[...] Each bitmask type can be implemented
as an enumerated type that overloads certain operators, as an integer type, or as a bitset (20.5).
This means, even though there is a bitset compilers still have some freedom how to implement it.
The precise definition of the members you ask about is defined in 27.5.3.1 Types [ios.types], and relevant points basically say they are bitmask types.
For one who has never written a line of C++11, and who has, at the moment, no opportunity to program in C++11, can you, in one short paragraph., tell me:
What is an "enum class" and why do we need it?
enum class is called a scoped enumeration. It prevents polluting the namespace where the enumeration appears with the names of the enumerators.
In C++03, you could do effectively the same thing by putting the enum inside a dedicated class. Perhaps that's the source of the syntax, which is a bit confusing.
Another difference is that the enumerators of such a type don't convert implicitly to int (static_cast<int> is required). This may be seldom needed but it makes it safe to overload a function taking an int argument with one taking enum type. You can be sure the int won't be called by accident. Or you can define pseudo-integral types with dedicated operator functions, and be sure that built-in operators won't interfere.
It's a bit annoying that these two unrelated differences come in the same package, and that you can't get an unscoped enumeration with no implicit conversion, but generally both changes are Good Things and enum class is a good default practice in C++11.
EDIT: A scoped enumeration is defined like this:
enum class duck { huey, dewey, louie };
and must be used with the scope resolution operator :: like this:
duck culprit = duck::huey; // or "auto culprit" to avoid redundancy
Note that the :: operator also works with C++03 unscoped enumerations, so the second line above would work even if the first was missing class.
This might be excessive detail, but class does not go into the elaborated-type-specifier if forward declaring the enumerated type, as in
void quack( enum duck whom ); // not "enum class"
However, there is a construct new in C++11, the opaque-enum-declaration, which does include the class keyword and defines a complete type.
enum duck; // duck is declared as incomplete type
enum class duck; // duck is now complete type; underlying type defaults to int
The keyword struct can be substituted for class with no semantic difference.
You can explicitly specify the storage type when the data size is important (packing it in a struct perhaps).
The enumeration values are scoped within the name of the enum only; before c++11 they leaked into the enclosing scope.
I seem to recall the conversion rules were also changed somewhat...
In relation to point one 1, the storage size of enums would change before C++11 depending on the largest value assigned to an enumeration. Usually it doesn't matter so much, but when it does you have to resort to ugly hacks to force the size.
As for point 3, in C++11 enums are not implicitly convertible or comparable to ints or other enum types: useful for avoiding function overloading headaches and other implicit conversion gotchas.
Personnally I have used it in a tcp based messaging protocol: many of the fields were enum values that I needed to encode inside one byte only, so as to respect the messaging interface..
All my enums were simply defined this way:
enum class EnumFieldA : unsigned char { eValProperty1, eValProperty2};
enum class EnumFieldB : unsigned char { eValProperty1, eValProperty2, eValProperty3};
enum class EnumFieldC : unsigned char { eValProperty1, eValProperty2, eValProperty3, eValProperty4};
...
there are also plenty of thorough answers in this SO question.
At first I was confused by your question, but I think you want to know the difference between c++ enum and that in c++11. As best as I can understand, in the later, you have strongly typed enums which allows you to scope your them. I think this explains it well. CHEERS
C++11 adds enum classes, which are stronger-typed enums - values of enum classes will not be implicitly converted to values of other enum classes or integers, and forward-declarations are permitted by virtue of an explicit size specifier.
Is it possible to pass values of such enumerations to varargs functions and remain within standards-defined behavior? Within implementation-defined behavior?
Yes, you can. 5.2.2/7 explicitly allows arguments of any enumeration type. Unscoped enum values are integer promoted, but scoped enums (the enum class ones) are not.
Of course you still have to be careful in the implementation of the function.
I think the answer is that it can be safe:
VA_ARGS requires arguments to be POD, that hasn't changed as far as I'm aware.
I can't see any reason why:
enum class foo { bar=1 };
Wouldn't meet the requirements for POD-ness though.
As you throw away some type information when using varargs (that's why it's strongly discouraged for non POD types) you will just receive the underlying type at the other end of your varargs using function. The default is int but you can change that (e.g. enum class MyEnum : char { ... };)
Corrected: varargs does indeed not throw away all type information and if you use POD data type you should be quite safe.
Why typedef can not be used with static? For example, the code below is an error
typedef static int INT2;
What other rules should be follow to use the typedef? What other keywords can not be used with typedef?
Thanks so much!
typedef doesn't declare an instance of a variable, it declares a type (type alias actually),
static is a qualifier you apply to an instance, not a type, so you can use static when you use the type, but not when you define the type. Like this..
typedef int int32;
static int32 foo;
The static keyword is not part of the type, depending on the context it is a storage or scope specifier and has no influence whatsoever on the type. Therefore, it cannot be used as part of the type definition, which is why it is invalid here.
A typedef is a type definition, i.e. you're saying 'this name' now refers to 'this type', the name you give must be an identifier as defined by the language standard, the type has to be a type specifier, i.e. an already named type, either base type or typedef'd, a struct, union, class, or enum specifier, with possible type qualifiers, i.e. const, or volatile.
The static keyword however does not change the type, it says something about the object, (in general, not in the OOP sense.) e.g. it is the variable that is placed in static storage, not the type.
It looks like you're trying to use a typedef as a macro, i.e.
#define MYINT static int
Storage duration is associated with objects. A typedef declaration creates an alias -- a new name for a type. It does not create objects. Hence you cannot use a storage specifier with a typedef.
typedef cannot be used along with static as both typedef and static are storage classes. If you define a variable as typedef static int a; then there exist multiple storage classes for the variable a.
Storage classes are used to define the scope (visibility) and life-time of variables and/or functions. Some examples are static, auto, register, extern, typedef etc.
As many other people have mentioned, static is a storage class specifier, not a type. What this means, specifically, is that the static keyword tells tells the compiler something about where a variable should be placed, whether or not it should appear as a symbol for external linking, or how long the variable should remain in existence.
A type is an interpretation of a memory location. It's a description of what kind of data lives in that location and comes associated with a set of operations that can be performed on that data.
So type and storage class are only related in that they both say something about a piece of data. The typedef keyword is for creating new names for types.
As for a random analogy...
A type is like talking about a specific make and model of car.
A storage class is like saying that a car is stored in a private heated garage and only used on a private racetrack.
A typedef is a nickname for a specific make and model.
I think the answers from wich and Bailey are correct and enough, but to help clarify to those that commented: When you declare a typedef the resulting type must be consistent everywhere it can be used. What if the typedef you created appears in the following code:
INT2 myfunction()
{
return 0;
}
class MyClass
{
public: INT2 x;
};
INT2 MyClass::x;
The function returning INT2 would make no sense. Of course the return value is not static (it can't be).
The x member declaration in MyClass would be static, and also its later definition? That's not only redundant, is incorrect, because you don't use the static keyword when defining a static member - only when declaring it.
The same applies to the other keywords mentioned by Bailey. Think about it: the only keywords that can declare consistently a type for all its uses are the primitive types themselves, and the type modifiers (const, unsigned, etc.).