Type long long
If you recall from lesson 2.4 -- Integers, the largest integer type C++03 defines is “long”. Long has a platform-specific size that can be either 32 or 64 bits. C++ defines a new type named long long that’s guaranteed to be at least 64 bits in length. Because “long long” was already introduced by C99, many compilers already supported it prior to C++11.
C++11 also imported the D.2.4a -- Fixed-width integers and the unsigned controversy from C99.
Type inference with auto and decltype
My favorite change in C++11 is the introduction of the auto keyword. Consider the common use case where you want to iterate through a vector using a for loop:
1 |
for (std::vector<int>::const_iterator itr = myvector.cbegin(); itr != myvector.cend(); ++itr) |
Having to determine that the data type for the iterator itr is “std::vector
That’s where the auto keyword comes in:
1 |
for (auto itr = myvector.cbegin(); itr != myvector.cend(); ++itr) |
The auto keyword tells the compiler to infer the type of the variable from its initializer.
1 2 3 4 |
auto x = 5; // x will be type int auto y = 5.5; // y will be type double auto z = y; // z will be type double auto w = "hi"; // w will be type const char* |
The decltype can be used to determine the type of an expression at compile-type.
1 2 3 |
decltype(5) x; // x will be type int because 5 is an int decltype(x) y = 6; // y will be type int because x is an int auto z = x; // z will type type int |
Although it may seem like auto and decltype will always deduce the same type, that isn’t the case, as shown by the following example:
1 2 3 |
const std::vector<int> v(5); // declare a vector v auto a = v[0]; // a will be type int because v[0] is an int decltype(v[0]) b = 1; // b will be type const int&, which is the return type of std::vector<int>::operator[](size_type) const |
Generally, if you need a type for a variable you are going to initialize, use auto. decltype is better used when you need the type for something that is not a variable, like a return type.
Type nullptr
In previous iterations of C and C++, 0 acted as both a constant integer and as the null pointer constant, which is why the following oddity occurs:
1 2 |
int *p = 1; // illegal, can't assign an int to an int* variable int *q = 0; // legal, 0 has a special meaning as a null pointer |
C++11 defines a new reserved identifier called nullptr (of type nullptr_t) that is not an integer, and can not be converted to an integer (though oddly enough, it can be converted to the boolean value false). 0 remains a valid null point constant for backwards compatibility purposes.
Enum classes
(Note: The following isn’t yet supported by Visual Studio 2010, but it’s simple enough to follow even without trying the examples yourself)
In C++03, enums are not type safe -- they are treated as integers even when the enumeration types are distinct. Consider the following case:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#include <iostream> using namespace std; int main() { enum Color { RED, BLUE }; enum Fruit { BANANA, APPLE }; Color a = RED; Fruit b = BANANA; if (a == b) // The compiler will compare a and b as integers cout << "a and b are equal" << endl; // and find they are equal! else cout << "a and b are not equal" << endl; return 0; } |
When C++ compares a and b, it’s comparing them as integers, which means in the above example, a does equal b since they both default to integer 0. This is definitely not as desired since a and b are from different enumerations!
C++11 defines a new concept, the enum class, which makes enums both strongly typed and strongly scoped.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
int main() { enum class Color { RED, BLUE }; enum class Fruit { BANANA, APPLE }; Color a = Color::RED; // note: RED is not accessible any more, we have to use Color::RED Fruit b = Fruit::BANANA; // note: BANANA is not accessible any more, we have to use Fruit::BANANA if (a == b) // compile error here, as the compiler doesn't know how to compare different types Color and Fruit cout << "a and b are equal" << endl; else cout << "a and b are not equal" << endl; return 0; } |
With normal enums, you can access enumerators (eg. RED) directly in the surrounding scope (eg. within main). However, with enum classes, the strong scoping rules mean you have to use a scope qualifier to access the enumerator (eg. Color::RED). This helps keep name pollution and the potential for name conflicts down.
The strong typing rules means that C++ will look for an explicitly defined comparison function to compare Color and Fruit. Since we haven’t defined an operator==(Color, Fruit) function, the compiler won’t understand how to compare a and b in any meaningful way, and this will cause a compile-time error to occur.
![]() |
![]() |
![]() |
It's help for me,
I think the first word of the first paragraph should be "if" instead of "in".
So many typos, so little time. :) Thanks for pointing that out.
Hi, it seems that the declaration of the overloaded subscript operator would be something like:
If that is correct, does that mean that the last ("const") in the comment below is a typo?
Thanks
sorry bad question, I've forgotten the meaning of const explained here: http://www.learncpp.com/cpp-tutorial/810-const-class-objects-and-member-functions/
There seems to be a quirk with VS10 that does not show up in g++. I'm using jGRASP with MinGW.
regarding the enum code above:
enum.cpp:16:13: warning: comparison between 'enum main()::Color' and 'enum main()::Fruit; [-Wenum-compare]
Seems like this desired behavior is already implemented here. The comparison is not allowed. I think I'm using C++98 because it won't let me do range-based for loops.
It also seems like it's using namespaces (or something similar) to reduce the scope of the enums.
From the 7th paragraph in your narrative, above:
The decltype can be used to determine the type of an expression at compile-type.
Alex, is "compile-type" supposed to be "compile-time"?
I know this is nitpicking but - auto is not new. What is new is the definition of auto.
It actually originally is in C (think carry over from B ?).
As the C FAQ points out about the auto keyword :
"One can imagine stylistic uses such as emphasizing that a variable must be automatic, and supposedly some compilers have used it to force a variable not to be in a register. "
And I seem to remember reading this years ago too - that that is what the use was (variable not in a register).
Again, nothing major important, so you can consider this nitpicking or trivia or ... whatever else.
Regarding B.2.
C++11 does have fixed integer types (section 18.4)
#include
C++11 example of enum struct lacks 'struct' or 'class' after enum:
(right after the sentence 'C++11 defines a new concept, the enum class, which makes enums both strongly typed and strongly scoped.')
Should be:
enum struct Color {
RED,
BLUE
};
enum struct Fruit {
BANANA,
APPLE
};
Thank you for noticing. Fixed!