Chapter 3 New Language Features
The New Language Features
nullptr and std::nullptr_t
nullptr : C++11定义的空指针类型; 在C中空指针类型NULL 的值为(void*)0, 而在原C++中NULL 的值为0, 即
#ifdef __cplusplus
#define NULL 0
#else
#define NULL (void*)0
#endif
当以前使用NULL时, 会出现歧义,或者调用不符合预期的情况, 而nullptr能比较好的解决这个问题。
void f(int);
void f(void*);
f(0); //call f(int)
f(NULL); //call f(int) if NULL is 0, ambiguous
f(nullptr); //call f(void*)
std::nullptr_t: 在< cstddef> 中定义:
namespace std
{
typedef decltype(nullptr) nullptr_t;
}
auto
根据右边所提供值的类型,来确定所定义的变量类型(右边必须提供值)
auto i; //error
auto i = 10; // i is int
Uniform Initialization and Initializer Lists
即:
//用法
int values[] { 1, 2, 3 };
std::vector<int> v { 2, 3, 5, 7, 11, 13, 17 };
std::vector<std::string> cities {
"Berlin", "New York", "London", "Braunschweig", "Cairo", "Cologne"
};
std::complex<double> c{4.0,3.0}; // equivalent to c(4.0,3.0)
//初始化为类型的初始值
int i; // i has undefined value
int j{}; // j is initialized by 0
int* p; // p has undefined value
int* q{}; // q is initialized by nullptr
当初始化列表中的值与定义的类型值不匹配时,所遵循的规则为(大吃小),即所定义的类型的值能否表示初始化列表中的值的类型。如果能,那么就不会产生错误,否则则会出错, 如:
int x1(5.3); // OK, but OUCH: x1 becomes 5
int x2 = 5.3; // OK, but OUCH: x2 becomes 5
int x3{5.0}; // ERROR: narrowing
int x4 = {5.3}; // ERROR: narrowing
char c1{7}; // OK: even though 7 is an int, this is not narrowing
char c2{99999}; // ERROR: narrowing (if 99999 doesn’t fit into a char)
std::vector<int> v1 { 1, 2, 4, 5 }; // OK
std::vector<int> v2 { 1, 2.3, 4, 5.6 }; // ERROR: narrowing doubles to ints
//
class P
{
public:
P(int,int);
P(std::initializer_list<int>);
};
P p(77,5); // calls P::P(int,int)
P q{77,5}; // calls P::P(initializer_list)
range for
std::vector<string> vs;
for(auto str : vs){
std::cout << str << std::endl;
}
Move Semantics and Rvalue References(move 语句与右值引用)
用于减少对象拷贝开销。
//move 定义与<utility>, 简单使用
X x;
coll.insert(x); // inserts copy of x (OK, x is still used)
...
coll.insert(x+x); // moves (or copies) contents of temporary rvalue
...
coll.insert(std::move(x)); // moves (or copies) contents of x into coll
// = 号与constructor重载
class X {
public:
X (const X& lvalue); // copy constructor
X (X&& rvalue); // move constructor
...
X& operator= (const X& lvalue); // copy assignment operator
X& operator= (X&& rvalue); // move assignment operator
}
//
void foo(const X&); //如果没用定义void foo(X&&); 可接受右值引用
Raw String Literals
可用于构造复杂的表达式。
R"nc(a\
b\nc()"
)nc" = "a\\\n b\\nc()\"\n "
Keyword noexcept
使函数不会抛出异常,如果抛出,程序会被 std::terminate()终止。(std::terminate() 里面默认调用std::absort()).
Keyword constexpr
可以在编译期间确定的值。
Variadic Templates
可变参数模板
void print ()
{
}
template <typename T, typename... Types>
void print (const T& firstArg, const Types&... args)
{
std::cout << firstArg << std::endl; // print first argument
print(args...); // call print() for remaining arguments
}
print (7.5, "hello", std::bitset<16>(377), 42);
output:
7.5
hello
0000000101111001
42
Alias Templates (Template Typedef)
用法:
template <typename T>
using Vec = std::vector<T,MyAlloc<T>>; // standard vector using own allocator
Vec<int> coll; //std::vector<int,MyAlloc<int>> coll;
Lambdas
仿函数式,定义及相关使用:
auto l = [] (const std::string& s) {
std::cout << s << std::endl;
};
l("hello lambda"); // prints ‘‘hello lambda’’
//或者
[] {
std::cout << "hello lambda" << std::endl;
} (); // prints ‘‘hello lambda’’
可以使用capture获取外部的参数,可以使用值传递[=]与引用[&]两种方式。
int x=0;
int y=42;
auto qqq = [x, &y] {
std::cout << "x: " << x << std::endl;
std::cout << "y: " << y << std::endl;
++y; // OK
};
x = y = 77;
qqq();
qqq();
std::cout << "final y: " << y << std::endl;
使用值传递的值,抓取后会“停留”在抓取的那个时候,不会外界值的改变而改变, 而使用引用传递则会因为外部改变而改变。
output:
x: 0
y: 77
x: 0
y: 78
final y: 79
加multable, 可使其内部,通过值传递进来的值,对其进行修改:
int id = 0;
auto f = [id] () mutable {
std::cout << "id: " << id << std::endl;
++id; // OK
};
id = 42;
f();
f();
f();
std::cout << id << std::endl;
//output
id: 0
id: 1
id: 2
42
Keyword decltype
decltype作为操作符,用于查询表达式的数据类型
Scoped Enumerations
使用:
//定义
enum class Salutation : char { mr, ms, co, none };
//用
Salutation::mr
Nontype Template Parameters
例子:
bitset<32> flags32; // bitset with 32 bits
bitset<50> flags50; // bitset with 50 bits
Default Template Parameters
用法:
template <typename T, typename container = vector<T>>
class MyClass;
MyClass<int> x1; // equivalent to: MyClass<int,vector<int>>
Member Templates
成员模板函数:
class MyClass {
//...
template <typename T>
void f(T);
};
一些使用需要注意的地方:
template <typename T>
class MyClass {
private:
T value;
public:
void assign (const MyClass<T>& x) { // x must have same type as *this
value = x.value;
}
//...
};
//使用
void f()
{
MyClass<double> d;
MyClass<int> i;
d.assign(d); // OK
d.assign(i); // ERROR: i is MyClass<int>
// but MyClass<double> is required
}
//解决方法
template <typename T>
class MyClass {
private:
T value;
public:
template <typename X> // member template
void assign (const MyClass<X>& x) { // allows different template types
value = x.getValue();
}
T getValue () const {
return value;
}
//...
};
void f()
{
MyClass<double> d;
MyClass<int> i;
d.assign(d); // OK
d.assign(i); // OK (int is assignable to double)
}
模板构造函数使用:
template <typename T>
class MyClass {
public:
// copy constructor with implicit type conversion
// - does not suppress implicit copy constructor
template <typename U>
MyClass (const MyClass<U>& x);
//...
};
void f()
{
MyClass<double> xd;
//...
MyClass<double> xd2(xd); // calls implicitly generated copy constructor
MyClass<int> xi(xd); // calls template constructor
//...
}