C++11/14
提示:这里可以添加本文要记录的大概内容:
Header files
C++标准库的header files不带副档名(.h) ,例如#include<vector> 新型C header files 不带副名称.h ,例如#include<cstdio> 旧型C header files 带副名称,仍可用,例如#include<stdlib.h>
简单测试VS2018的支持C++版本
#include<vector>
#include<iostream>
#include<cstdio>
#include<stdlib.h>
using namespace std;
int main() {
cout << __cplusplus << endl;
}
调节项目属性,改起支持C++14:
Variadic Templates
可以很方便的完成recursive function call
void print() {
}
template<class T, typename... Type>
void print(const T first, const Type&... args) {
cout << first << endl;
print(args...);
}
template<typename... Type>
void print(const Type& ... args) {
}
int main() {
print(1, "hello", 'c', bitset<16>(377));
}
成功输出:
应用于Hash映射
class Customer {
public:
string fname;
string lname;
int no;
};
template<typename T>
inline void hash_combine(size_t& seed, const T& val) {
seed ^= std::hash<T>() + 0x9e3779b9
+ (seed << 6) + (seed >> 2);
}
template<typename T, typename... Type>
inline void hash_val(size_t& seed, const Type&... args) {
hash_combine(seed, val);
hash_val(seed, args...);
}
template<typename... Type>
inline size_t hash_val(const Type& ... args) {
size_t seed = 0;
hash_val(seed, args...);
return seed;
}
class CustmerHash {
public:
std::size_t operator()(const Customer& c) const {
return hash_val(c.fname, c.lname, c.no);
}
};
Tuple的实现
template<typename... Values> class tuple;
template<> class tuple<> {};
template<typename Head, typename... Tail>
class tuple<Head, Tail...>
:private tuple<Tail...>
{
typedef tuple<Tail...> inherited;
public:
tuple() {}
tuple(Head v, Tail... vtail)
:m_Head(v), inherited(vtail...) {}
typename Head::type head() { return m_Head; }
inherited& tail() { return *this; }
protected:
Head m_Head;
};
部分细节
Spaces in Template Expressions
vector<list<int> >;
vector<list<int>>;
nullptr and std::nullptr_t
C++允许使用nullptr 代替0 或NULL ,
void f(int);
void f(void*);
f(0);
f(NULL);
f(nullptr);
\include\stddef.h
typedef declttype(nullptr) nullptr_t;
auto用法
auto可以让编译器进行自行推导; type比较复杂时可以进行使用
vector<string> v;
auto pos = v.begin();
auto l = [](int x)->bool {
};
Uniform Initialization
其实编译器看到{t1,t2,t3....} 都在做一件事情,做出来一个initializer_list<T> ,它关联到一个array<T, n> ,调用函数时候该array元素可以被编译器分解逐一传给函数,但如果函数参数是一个initializer_list<T> ,调用者却不能给予
int values[]{ 1,2,3 };
vector<int> v{ 2,3,5,7 };
vector<string> cities{
"Berlin", "Beijing", "London"
};
complex<double>c{ 4.0,3.0 };
Initializer Lists
int i;
int j{};
int* p;
int* q{};
但是,编译器不允许进行类型转换
int x1(5.3);
int x2 = 5.2;
int x3{5.0};
int x4 = {5.2};
例子使用:
class P
{
public:
P(int a, int b) {
cout << "P(int, int), a = " << a << " , b = " << b << endl;
}
P(initializer_list<int> initlist) {
cout << "P(initializer_list<int>), values= ";
for (auto i : initlist) {
cout << i << endl;
}
}
};
P p(77, 5);
P q{77, 5};
P r{3, 77, 5};
P s = {77, 5};
如果只有构造函数1,那么编译器会将list个数为2的拆解,调用构造函数1,例如q与s会正常运行,利用构造函数1被赋值。
explicit for ctors taking more than one argument
主要用于构造函数,防止隐式的转换
class P
{
public:
P(int a, int b) {
cout << "P(int, int), a = " << a << " , b = " << b << endl;
}
P(initializer_list<int> initlist) {
cout << "P(initializer_list<int>), values= ";
for (auto i : initlist) {
cout << i << endl;
}
}
explicit P(int a, int b, int c) {
cout << "explicit(int a, int b, int c)\n";
}
};
P p1(77, 5);
P p2{ 77, 4 };
P P5 = (33, 2, 1);
range-based for statement
for( decl : coll){
statement;
}
实际上编译器会这样做:
for(auto _pos = coll.begin(), _end = coll.end(); _pos != _end; ++_pos){
decl = *_pos;
statement;
}
class C {
public:
explicit C(const string& s);
};
vector<string> vs;
for (const C& elem : vs) {
cout << elem << endl;
}
=default, = delete
=delete是需要这个函数; =default是使用编译器给的版本;
class Zoo
{
private:
int d1, d2;
public:
Zoo(int i1, int i2) {}
Zoo(const Zoo&) = delete;
Zoo(Zoo&&) = default;
Zoo& operator=(const Zoo&) = default;
Zoo& operator=(const Zoo&&) = delete;
virtual ~Zoo() {}
};
C++编译器会给类的一些函数提供默认版本,拷贝构造函数、复制构造函数、无参数构造函数以及析构函数。
如果一个类带有pointer则一定需要Big-Three(拷贝构造、复制构造以及析构),如果没有指针,则大部分都不需要进行复写Big- Three;
对于string,一定有Big-Three,而且有Big-Five;
No-Copy and Private-Copy
struct NoCopy
{
NoCopy() = default;
NoCopy(const NoCopy&) = delete;
NoCopy& operator=(const NoCopy&) = delete;
~NoCopy() = default;
};
class PrivateCopy {
private:
PrivateCopy(const PrivateCopy&);
PrivateCopy& operator=(const PrivateCopy&);
public:
PrivateCopy() = default;
~PrivateCopy();
};
struct NoDtor
{
NoDtor() = default;
~NoDtor() = delete;
};
NoDtor nd;
NoDtor* p = new NoDtor();
delete p;
Alias Template
template <typename T>
using Vec = std::vector<T, Myalloc<T>>;
Vec<int> coll;
下面的程序会报错: Error:Container is not a template
template<typename Container, typename T>
void test_moveable(Container cntr, T elem) {
Container<T> c;
for (int long i = 0; i < 1000; ++i) {
c.insert(c.end(), T());
}
Container<T> c1(c);
Container<T> c2(std::move(c));
c1.swap(c2);
}
采用function template + iterator + traits解决:
template<typename Container>
void test_moveable(Container c) {
typedef typename iterator_traits<typename Container::iterator>::value_type Valtype;
for (int long i = 0; i < 1000; ++i) {
c.insert(c.end(), Valtype());
}
Container c1(c);
Container c2(std::move(c));
c1.swap(c2);
}
template template parameter
template<typename T>
using Vec = vector<T, allocator<T>>;
template <typename T>
using Lst = list<T, allocator<T>>;
template <typename T>
using Deq = deque<T, allocator<T>>;
template<typename T, template<typename>typename Container>
class XCls
{
private:
Container<T> c;
public:
XCls() {
for (long i = 0; i < 1000; ++i) {
c.insert(c.end(), T());
}
Container<T> c1(c);
Container<T> c2(std::move(c));
c1.swap(c2);
}
};
Xcls<MyString, vector> c1;
XCls<MyString, Vec>v1;
XCls<MyStrNoMove, Vec>v2;
Type Alias
using func = void(*)(int, int);
void example(int, int){}
func fn = example;
using
using namespace std;
using std::cout;
protected:
using _Base::_M_allocate;
using _Base::_M_deallocate;
using func = void(*)(int, int);
noexcept
函数后面加上这个关键字,可以保证这个函数不会丢出异常; 如果有异常没有处理,会向上调用,程序终止
void foo() noexcept -> void foo() noexcept(true);
移动构造函数不能抛出异常,这样才会被调用
class MyString
{
private:
char* _data;
size_t _len;
public:
MyString(MyString&& str) noexcept
: _data(str._data), _len(str._len) {}
MyString& operator=(MyString&& str)noexcept {
return *this;
}
override
struct Base
{
virtual void vfunc(float) {}
};
struct Derived1 :Base {
virtual void vfunc(int) {}
};
struct Derived2:Base
{
virtual void vfunc(float) override {}
};
final
final表示最后,表示类不能被继承;虚函数不能被覆盖
struct Base1 final {};
struct Derived3:Base1{};
struct Base2{
virtual void f() final;
}
struct Derrived2:Base2{
void f();
}
decltype
使用关键字,可以知道表达式的类型(typeof)
map<string, float> coll;
decltpye(coll)::value_type elem;
template<typename T1, typename T2>
decltype(x + y) add(T1 x, T2 y);
template<typename T1, typename T2>
auto add(T1 x, T2 y)->decltype(x + y);
tyoedef typename decltype(obj)::iterator iType;
typedef typename T::iterator iType;
auto cmp = [](const Person& p1, const Person& p2){
return .....
}
std::set<Person, decltype(cmp)> coll(cmp);
Lambdas
[...](...)mutable throw -> retType{...}
[]{
std::cout<<"hello lambda"<<std::endl;
}();
auto l = []{
std:: cout << "hello lambda" << endl;
};
l();
int id = 0;
auto f = [id]()mutable {
std::cout << id << std::endl;
++id;
};
class Functor{
private:
int id;
public:
void oprator()(){
std::cout << id << std::endl;
++id;
}
}
Variadic Templates
利用函数参数个数(类型)的逐渐递减来完成函数的递归 例1:如上
void print() {
}
template<class T, typename... Type>
void print(const T first, const Type&... args) {
cout << first << endl;
print(args...);
}
template<typename... Type>
void print(const Type& ... args) {
}
int main() {
print(1, "hello", 'c', bitset<16>(377));
}
例子2:
int* pi = new int;
printf("%d %s %p %f\n", 15, "This is Ace", "pi", "3.1415926");
void printf(const char* s) {
while (*s) {
if (*s == '%' && *(++s) != '%') {
throw std::runtime_error("invalid format string :: missing argument");
}
std::cout << *s++;
}
}
template<typename T, typename... Args>
void printf(const char* s, T value, Args... args) {
while (*s) {
if (*s == '%' && *(s++) != '%') {
std::cout << value;
printf(++s, args...);
return;
}
std::cout << *s++;
}
throw std::logic_error("extra arguments provided to printf()");
}
例子3: 参数类型一样,个数不定,直接使用initializer_list 就可以。
cout << max({57, 48, 60, 100, 20, 18});
例子4:
int maxinum(int n) {
return n;
}
template<typename... Args>
int maxinum(int n, Args... args) {
return std::max(n, maxinum(args...));
}
cout << maxinum(57, 48, 60, 100, 20, 18) << endl;
例子5:递归输出 sizeof...() 可以获得元素个数
template<typename... Args>
ostream& operator<<(ostream& os, const tuple<Args...>& t) {
os << "[";
PRINT_TUPLE<0, sizeof...(Args), Args...>::print(os, t);
os << "]";
}
template<int IDX, int MAX, typename... Args>
struct PRINT_TUPLE
{
static void print(ostream& os, const tuple<Args...>& t) {
os << get<IDX>(t) << (IDX + 1 == MAX ? "" : ",");
PRINT_TUPLE<IDX + 1, MAX, Args...>::print(os, t);
}
};
template<int MAX, typename...Args>
struct PRINT_TUPLE
{
static void print(std::ostream& os, const tuple<Args...>& t) {}
};
cout<<make_tuple<7.5, string("hello"),22>;
例子6:递归继承
template<typename... Values> class tuple;
template<> class tuple<> {};
template<typename Head, typename... Tail>
class tuple<Head, Tail...>
:private tuple<Tail...>
{
typedef tuple<Tail...> inherited;
public:
tuple() {}
tuple(Head v, Tail... vtail)
:m_Head(v), inherited(vtail...) {}
auto head()->decltype(m_Head) { return m_Head; }
inherited& tail() { return *this; }
protected:
Head m_Head;
};
Rvalue references
右值引用
class MyString {
public:
static size_t DCtor;
static size_t Ctor;
static size_t CCtor;
static size_t CAsgn;
static size_t MCtor;
static size_t MAsgn;
static size_t Dtor;
private:
char* _data;
size_t _len;
void init_data(const char* s) {
_data = new char[_len + 1];
memcpy(_data, s, _len);
_data[_len] = '\0';
}
public:
MyString() :_data(nullptr), _len(0) { ++Dtor; }
MyString(const char* p) :_len(strlen(p)) {
++Ctor;
init_data(p);
}
MyString(const MyString& str) : _len(str._len) {
++CCtor;
init_data(str._data);
}
MyString(MyString&& str) :_data(str._data), _len(str._len){
str._data = nullptr;
str._len = 0;
}
MyString& operator=(MyString& str) noexcept {
++CAsgn;
if (this != &str) {
if (_data) delete _data;
_len = str._len;
init_data(str._data);
}
else {}
return *this;
}
MyString& operator=(MyString&& str) noexcept {
++MAsgn;
if (this != &str) {
if (_data) delete _data;
_len = str._len;
_data = str._data;
str._data = NULL;
str._len = 0;
}
return *this;
}
virtual ~MyString() {
++Dtor;
if (_data) {
delete _data;
}
}
};
|