chapter 18

18 Visiting with the new c++ standard

#
# C++11 Features Revisited
#
# New Types

c++11 adds the long long and unsigned long long types
to support 64-bit integers and the char16_t and
char32_t types to support 16-bit and 32-bit character
representtations,respectively.It also adds the "raw"
string.

# Uniform Initialization

brace-enclosed list(list-initialization) can be used
with all built-in types and with user-defined types
(that is,class objects). The list can be used either
with or without the = sign:
int x = {5};
short quar[5] {4,5,2,76,1};
int * ar = new int[4] {2,4,6,7} //c++11
Stump s1(3,15.6); //old style
Stump s2{5,43.4}; //c++11
Stump s3 = { 4,32.1}; //c++11
# Narrowing

char c1 = 1.57e27; //double to char,undefined behavi
char c2 = 459585821;//int to char,undefined behavior

char c1 {1.57e27} //complie time error
char c2 = 459585821;//compile time error out of range

# std::initializer_list

vector<int> a1(10); //10 elements
vector<int> a2{10}; // 1 element set to 10
vector<int> a3{4,6,1}; //3 elements set to 4 6 1;

begin() and end() member functions.

# Declarations

auto

decltype: creates type indicated by an expression.

decltype(x) y;
Here means: make y the same type as x, where x is a
expression.

double x;
int n;
decltype(x*n) q; //q same type as x*n, i.e.,double
decltype(&x) pd; //pd is type of double *

template<typename T, typename U)
void ef(T t, U u)
{
decltype(T*U) tu;
...
}

int j = 3;
int &k = j;
const int &n = j;
decltype(n) i1; //i1 const int &
decltype(j) i2; //i2 int
decltype((j)) i3; //i3 int &
decltype(k+1) i4; //i4 int
# Trailing Return Type

double f1(double,int); //traditional syntax
auto f2(double,int) -> double; //new syntax

template<typename T, typename U)
auto eff(T t,U u) -> decltype(T*U)
{
...
}

The problem that's addressed here is that T and U are
not in scope before the comiler reads the eff parame-
ter list,so any use of decltype has to come after the
parameter list.The new syntax makes that possible.

# Template Aliases: using =

typedef std::vector<std::string>::iterator iType;

c++11:

using itType = std::vector<std::string>::iterator;

The difference is that the new syntax also can be
used for partial template specialization,typedef cant

template<typename T>
using arr12 = std::array<T,12>;

std::array<double,12>a1;
std::array<std::string,12> a2;

can replaced with following:

arr12<double>a1;
arr12<std::string> a2;
# nullptr

# Smart pointers

All the new smart pointers have been designed to work
with STL containers and with move semantics.

unique_ptr shared_ptr weak_ptr

# Scoped Enumerations

enum Old1 {yes,no,maybe}; //traditional form
enum class New1{never,sometimes,often,always}; //new
enum struct New2{newer,lever,sever}; //new form

The new forms avoid name conflicts:

New1::never and New2::never
# Classes Changes

# explicit Conversion Operators

class Plebe
{
,,,
operator int() const;
explicit operator double()const;
...
};
...
Plebe a,b;
int n = a; //automatic conversion
double x = b; //not allowed
x = double(b); //explicit conversion, allowed

# Member In-Class Initialization

# Template and STL Changes

#
# Move Semantics and the Rvalue Reference
#
# The need for more semantics

The copy constructor can do the usual deep copy,while
the move constructor can just adjust the bookkeeping.
A move constructor may alter its argument in the pro-
cess of transferring ownership to a new object,and
this implies that an rvalue reference parameter
should not be const.

# Move Constructor Observations

There are two steps to enablement of move semantic

1. the rvalue reference allows the compiler to iden-
tify when move semantics can be used:

Useless two = one; //use Useless(const Useless&)
Useless four(one+ three) //use move semantics
The object one is an lvalue,so it matches the lvalue
reference,and the expression one + three is an rvalue
,so it matches the rvalue reference.

2. coding the move constructor so that it provides it

In short, Objects initialized with an lvalue object
use the "copy constructor",and objects initialized
with an rlvalue object use the "move constructor".

# Forcing a Move (page 1176)

#include <utility>
four = std::move(one); //forced move assignment

#
# New Class Features
#

# Specila Member Function

C++ adds two more special member functions (the move
constructor and the move assignment operator) to four
previous ones (the default constructor,the copy con-
structor,the copy assignment operator,and the des-
tructor). These are member functions that the compi-
ler provides automatically,subject to a variety of
conditions.

If you do provide a destructor or a copy constructor
or a copy assignment operator,the compiler does not
automatically provide a move constructor or a move a-
ssignment operator.

If you do provide a move constructor or a move
assignment operator,the compiler does not automaiti-
cally provide a copy constructor or a copy assignment
operator.

# Defaulted and Deleted Methods

if you provide a move constructor,then the default
constructor,the copy constructor,and the copy
assignment operator are not provide. In that case,you
can use the keyword "default" to explicitly declare
the defaulted versions of these methods:

class Someclass
{
public:
Someclass(Someclass &&);
Someclass() = default; //use default
Someclass(const Someclass &) = default;
Someclass & operator=(cosnt Someclass &) =
default;
...
};

"delete" keyword can be used to prevent the compiler
from using a particular method.For example,to prevent
an object from being copied,you can disable the copy
constructor and copy assignment operator:

Class Someclass
{
public:
Someclass() = default;
// disable copy constructor and copy assignment:
Someclass(const Someclass &) = delete;
Someclass & operator=(const Someclass &) =
delete;
// use default move constructor and move assignmt
Someclass(Someclass &&) = default;
Someclass & operator=(Someclass &&) = default;
Someclass & operator+(const Someclass&) const
...
};

Only the six special member functions can be default
,but you can use delete with any member function.

class Someclass
{
void redo(double);
void redo(int) = delete;
}

# Delegating Constructors (指定,委派)

C++11 allows you to use a construcnt as part of the
definition of another constructor.This process is
termed "delegation". Delegation uses a variant of the
member initialization list syntax:

class NOte
{
int k;
double x;
std::string st;

public:
Note();
Note(int);
Note(int,doulbe,std::string);
};

Note::Note(int kk,double xx,std::string stt):k(kk),
x(xx),st(stt) { }
Note::Note(): Note(0,0.01,"oh") {}
Note::NOte(int xx):Note(xx,0.01,"oh"){ }
# Inheriting Constructors

C++98 already had a syntax for making functions from
a namespace available:

namespace Box
{
int fn(int) { ... }
int fn(double) { ... }
int fn(const char *) { ... }
}

using Box::fn;//makes all overloaded fn available.
the same technique works for making nonspecial member
functions of a base class availabe to a derived class
.

class C1
{
...
public:
...
int fn(int j) {...}
double fn(double w){...}
void fn(const char * s){...}
};

class C2:public C1
{
...
public:
...
using C1::fn;
double fn(double){...}//overload the c1 one.
};

C++11 brings the same technique to constructors.All
the constructors of the base class,other than the
default,copy,and move constructors,are brought in as
possible constructors for the derived class,but the
ones that have function signatures matching derived
class constructors aren't used:

# Managing Virtual Methods: override and final (P1183)

With C++11,you can use the virtual specifier:
override to indicate that you intend to override a
virtual function.Place it after the parameter list.

If you want to prohibit derived classes from over-
riding a particular virtual method.To do so,place
"final" after the parameter list.

Virtual void f(char ch) const final {cout<<val();}

#
# Lambda Functions
#

# The How of Function Pointers,Functors,and lambadas

The three approaches for passing information to an
STL algorithm:function pointers,functors,and lambdas.

generate(vetor.begin(),vector.end,std::rad);
The generate()function takes a range,and sets each
element to the value returned by the third argument
,which is a function object that takes no arguments
.In this case,the function object is a pointer to
the standard rand() function.
count_if().

count3 = std::count_if(numbers.begin(),numbers.end(),
f_mod(3)); //page 1186

class f_mod
{
private:
int dv;
public:
f_mod(int d = 1): dv(d){}
bool operator()(int x) {return x % dv == 0;}
};

f_mod obj(3); //f_mod.dv set to 3
bool is_div_by_3 = obj(7); // as obj.operator()(7)

An anonymous function defination -- a lambda.:

[] (int x) {return x % 3 == 0;}

It looks much like the defination of f3():

bool f3(int x) {return x % 3 == 0;}

The difference is that there is no declared return
type. The return type is the type that decltype would
deduce from the return value.

If the lambda doesn't have a return statement,the
type is deduced to be void.

count3 = std::count_if(numbers.begin(),numbers.end(),
[](int x){return x % 3 == 0;});

That is,you use the entire lambda expression as you
would use a pointer or a functor constructor.

The automatic type deduction for lambdas works only
if the body consists of a single return statement.
Otherwise,you need to use the new trailing-return
-value syntax:

[ ] (double x) ->double {int y = x; return x-y;}
// return type is double

auto mod3 = [ ] (int x) {return x % 3 == 0;}
count 1 = std:count_if(n1.begin(),n1.end(),mod3);

bool result = mod3(z); //result is true if z % 3== 0

A named lambda can be defined inside a function.


Variables to be used are captured by having their
names listed within the brackets.

[zhao] // zhao is accessed by value.
[&zhao] // zhao is accessed by reference.
[&] // access to all the automatic variables
//by reference.
[=] // access to all the auto variable value
[zhao,&xian]
[&,zhao] //zhao by value all, other by reference
.... //can mix and match [=,&zhao]

 

int count13;
count13 = std::count_if(numbers.begin(),numbers.end()
,[](int x) { return x % 13 == 0;};
can replaced by:

int count13 = 0;
std::for_each(numbers.begin(),numbers.end(),
[&count13](int x){count13 += x % 13 == 0;});


int count3 = 0;
int count13 = 0;
std::for_each(numbers.begin(),numbers.end(),
[&](int x) {count3 += x%3 == 0;count13 +=x%13==0;
});


#
# Wrappers
#

C++ provides several wrappers or adapters.These are
objects used to provide a more uniform or more appro-
priate interface for other programming elements.For
example, bind1st and bind2nd,which adapt functions

# The function Wrapper and Template Inefficiencies

Because of callable types,Template would produces
more than one instantiations which is not efficient.
(page 1192)
# Fixing the problem

The function wrapper lets you rewrite the program so
that it uses just one instantiation.

The "function" template,declared in the functional
header file,specifies an object in terms of a call
signature,and it can be used to wrap a function poin-
ter,function object,or lambda expression having the
same call signature:

std::function<doulbe(char,int)> fdci;

You can then assign to fdci any function pointer,fun-
ction object,or lambda expression that takes type
char and int arguments and return type double.

# Further Options

typedef function<double(double)> fdd; //simplify ...
cout << use_f(y,fdd(dub)) << endl; //create and initi
cout << use_f(y,fdd(square)) << endl;
...

Another approach is to adapt the type of the formal
parameter f to original arguments.This can be done by
using a function wrapper object as the second para-
meter for the use_f() temlate definition:

#include <functional>
template <typename T>
T use_f(T v,std::function<T(T)> f) //f call signa-
{ //ture is T(T)
static int count = 0;
...
return f(v);
}

then the function calls can look like this:

cout << " "<<use_f<double>(y,dub) << endl;
...
cout << " "<<use_f<double>(y,Fp(5.0))<<endl;
...
cout <<use_f<double>(y,[](double u){return u*u;});

#
# Variadic Template
#

"Variadic" template provide a means to create templa-
te functions and template classes that accept a
variable number of arguments.

# Template and Function Parameter Packs

C++11 provides an ellipsis meta-operator that enables
you to declare an identifier for a template parameter
pack,essentially a list of types.Similarly,it lets
you declare an identifier for a function parameter
pack,essentially a list of values:

# Unpacking the packs


template<typename... Args> //Args is a pack
void show_list1(Args... args) //args is pack
{
show_list1(args...); //passes unpacked args
}

# Using Recursion in Variadic Template Functions

template<typename T,typename... Args>
void show_list3( T value,Args... args)

show_list3(const Args&... args); //const & for all

#
# More c++11 Features
#

The keyword thread_local is used to declare varibles
having static storage duration relative to a parti-
cular thread;thatis,they expire when the thread in
which they are defined expires.

# Library Additions (page1202)

# Low-Level Programming


#
# Language Change
#
#
# What Now?

posted @ 2017-09-12 20:08  孤灯下的守护者  阅读(176)  评论(0编辑  收藏  举报