#include<iostream>
#include<unistd.h>
#include<bitset>
#include<tuple>
#include<vector>
#include<list>
#include<string>
#include<algorithm>
#include<complex>
#include<map>
using namespace std;
/*可变参数适合用来做递归*/
/*
Variadic Templates
数量不定的模板参数
所以一定要写一个最后一个要用的函数
...就是一个所谓的pack(包)
用于template parameters,就是template parameters pack(模板参数包)
用于function parameter types,就是function parameter typs pack(函数参数类型包)
用于function parameters,就是function parameters pack(函数参数包)
*/
/**********************/
void print()
{
}
template<typename T,typename...Types>
void print(const T&firstarg,const Types&...args)//在可变模板参数中,可以用sizeof...(args) 计算出可变模板参数个数
{
cout << "print1" << endl;
cout << firstarg << endl;
print(args...);
}
template<typename...Types>
void print(const Types&...args)//在可变模板参数中,可以用sizeof...(args) 计算出可变模板参数个数
{
/*...*/
cout << "print2" << endl;
}
/**Variadic Templates 1****/
//模板有特化和泛化的概念,谁更特化调用谁
/*template:function templates/class templates
变化的是:template parameters
参数个数 vaiable number 利用参数个数逐一递减来实现递归,使用fuction template
参数类型 different type 利用参数个数逐一递减导致参数类型也逐一递减实现递归继承或者递归复合,使用class template
void func(){}
template<typename T,typename...Types>
void func(const T& firstarg,cont Typs&...args)
{
func(args...);
}
*/
//EXAMPLE 1 FUNCTOINTEMPLATE 打印各式各样的参数
void printX()
{}
template<typename T,typename...Types>
void printX(const T&firstarg,const Types&...args)
{
cout << firstarg << endl;
printX(args...);
}
void testVdctmp()
{
printX(7.5,"HELLO",bitset<16>(377),42);
}
//例子2 实现C的print功能
void print(const char*s)
{
while(*s)
{
if(*s == '%' && *(++s)!='%')
{
throw runtime_error("less args");
}
cout << *s;
break;
}
}
template<typename T,typename...types>
void print(const char*s,T value,types...args)
{
while(*s)
{
if(*s == '%' && *(++s)!='%')
{
cout << value << ' ';
print(++s,args...);
return;
}
cout << *s++;
}
throw logic_error("guoduo value!");
}
void testprint()
{
int *pi = new int;
print("%d%s%p%f\n",15,"this is ace",pi,3.1415926);
}
//例子3标准库实现max({})
void testmax()
{
cout << max({54,16,48,5})<<endl;
}
//例子4标准库实现maxmum()
int maxmum(int n)
{
return n;
}
template<typename...Type>
int maxmum(int n,Type...args)
{
return max(n,maxmum(args...));
}
void testmaxmum()
{
cout << maxmum(54,16,48,5)<<endl;
}
//例子五 实现按格式输出
//实现一个可变参数类模板的递归创建
template<int idx,int max,typename...args>
struct PRINT_TUPLE
{
static void printtestslf(ostream& os,const tuple<args...>& t)
{
os << get<idx>(t) << (idx+1 == max ? "":",");
PRINT_TUPLE<idx+1,max,args...>::printtestslf(os,t);//创建一个类并且立刻调用他的函数
}
};
//递归需要设置边界操作或者边界类
template<int max,typename...args>
struct PRINT_TUPLE<max,max,args...>
{
static void printtestslf(ostream& os,const tuple<args...>& t)
{
}
};
//开始重载<<
template<typename...args>
ostream& operator<<(ostream& os,const tuple<args...>& t)
{
os << "[";
//实现一个可变参数类模板的递归调用
PRINT_TUPLE<0,sizeof...(args),args...>::printtestslf(os,t);
return os << "]";
}
void testprintslf()
{
//希望格式输出格式: [7.5,hello,0000000101111001,42]
//思路:首尾不同格式,中间用,末尾不用,
//需要知道整个tuple的数字个数 size
//需要知道输出字符的位置
//make_tuple 是把后面这一串数据放在一个tuple里面送给 out所以需要重载<<
cout << make_tuple(7.5,string("hello"),bitset<16>(377),42) << endl;
}
//例子6
//可变类模板递归继承
//tuple的标准库中
//inherited& tail(){return *this;} --->把当前对象指针强制转成只有tail()大小的指针,本来是指向本身的指针,现在通过inherited进行了强转,要注意tuple的村粗方式
/*
------ <-----this本来指向这一整个类的这个位置,通过inherited强转后,就指向 只到6.3这个部分位置了
| |
|6.3 |
|4 |
------
*/
template<typename...args>class tuple1;//这两个是可变类模板的递归继承的边界类模板
template<>class tuple1<>{};
template<typename Head,typename...Tail>
class tuple1<Head,Tail...>
:private tuple1<Tail...>
{
typedef tuple1<Tail...> inherited;
protected:
Head m_head;
public:
tuple1(){}
tuple1(Head v,Tail...tail):m_head(v),inherited(tail...){}
//函数 "tuple1<Head, Tail...>::head [其中 Head=std::string, Tail=<float>]" (已声明 所在行数:197) 不可访问
//typename Head::type head(){return m_head;}
//auto head()->decltype(m_head){return m_head;}
Head head(){return m_head;}
inherited& tail(){return *this;}
};
void testtuple1()
{
tuple1<int,string,float> tpl(1,"hello",2.0);
cout << tpl.head() << endl;
}
//例子7
template<typename...Tail>class tuple2;
template<>class tuple2<>{};
template<typename Head,typename...Tail>
class tuple2<Head,Tail...>
{
typedef tuple2<Tail...> composited;//创建一个递归类
protected:
Head m_head;
composited m_tail;
public:
tuple2(){};
tuple2(Head v,Tail...tail):m_head(v),m_tail(tail...){}
Head head(){return m_head;}
composited& tail(){return m_tail;}
};
void testcomptuple()
{
tuple2<int,string,float> t(1,"test",3.3);
cout << t.head() << endl;
cout << t.tail().head() << endl;
cout << t.tail().tail().head() << endl;
}
/**variadic template********/
/*nullptr*/
void f(int)
{
cout << "int" << endl;
}
void f(void*)
{
cout << "void*" <<endl;
}
void test04()
{
f(0);//call int
// f(NULL);//call f(int) if NULL is 0,会有告警,编译器不知道调什么玩意
f(nullptr);//call f(void*)
}
/*------nullptr end------*/
/********auto*************/
void test01()
{
auto i = 42;//i has type int
//double f();
//auto d = f();//d has type double;
//auto一般用在type很长或者很复杂的地方
//using auto is especially useful where the type is a pretty long and/or complicated expression.
//For example
vector<string> v;
v.push_back("aa");
v.push_back("bb");
v.push_back("cc");
auto pos = v.begin(); //pos has type vector<string>::iterator
//l has the type of a lambda taking an int and returning a bool
//lambda 没有名称的仿函数
//this latter is an object,representing a lambda
auto l = [](int x)->bool{};
list<string> lc;
lc.push_back("aa");
auto ite = find(lc.begin(),lc.end(),"aa");
}
/********auto end*********/
/********uniform initialization******/
/*困惑与(小括号,大括号,赋值)*/
/*任何初始化都可以用大括号*/
/*编译器看到{},会生成一个initializaer_list<T> 关联至array<T,n>*/
void test02()
{
int valus[] {1,2,3};
vector<int> v {1,2,3,5,7,11,13,17};
vector<string> cities {
"Berlin","New York","London","Cologne"
};
complex<double> c{4.0,3.0};//equivalent to c(4.0,3.0)
}
/********uniform initialization end******/
/****initializer lists********/
/***如果两个 initializer list拷贝 只是浅拷贝,要注意intializer list里面存的是array的指针**/
void print(initializer_list<int> vals)
{
//for(auto p = vals.begin();p != vals.end();++p)
for(auto p : vals)
{
cout << p << endl;
}
}
void test03()
{
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);
int x2 = 5.3;
//int x3{5.4};//error narror
//int x4 = {5.4};//error narrow
char c1{7};
//char c2{9999}; //error g++是Ok的
vector<int> v1{1,2,4,5};
//vector<int> v2{1,2.3,4,5.6};//error narrow
print({1,3,4,5,7});
}
class P
{
public:
P(int a,int b)
{
cout << "P(int a, int b), a= " << a << ",b="<<b<<endl;
}
P(initializer_list<int> initlist)
{
cout<<"P(initializer_list<int>),values= ";
for(auto i : initlist)
cout << i << " ";
cout << endl;
}
};
void test05()
{
P p(77,5);//int,int
P q{77,5}; //initializer_list
P r{77,5,42};//intializer_list
P s={77,5};//initializer_lis
}
void test06()
{
vector<int> v1 {2,5,7,13,69,83,50};
vector<int> v2( {2,5,7,13,69,83,50});
vector<int> v3;
v3 = {2,5,7,13,69,83,50};
v3.insert(v3.begin()+2,{0,1,2,3,4});
for(auto i:v3) //这个是c++11的新特性
cout << i << " ";
cout << endl;
cout << max({string("ace"),string("stacy"),string("sabrine")})<<endl;
cout << min({string("ace"),string("stacy"),string("sabrine")})<<endl;
cout << max({54,16,48,5})<<endl;
cout << min({54,16,48,5})<<endl;
}
/****initializer lists end****/
/***range_based for statement***/
/*
for(decl : coll)
{
statement;
}
*/
void test08()
{
for(int i : {2,3,4,5,6,7,8,9})
{
cout << i << endl;
}
vector<string> vec;
vec.push_back("bb");
for(auto& elem:vec) //赋值
{
elem += "aa";
}
for(auto elem1:vec) //读取出值
{
cout << elem1 << " ";
}
cout << endl;
}
/***range_based for statement end***/
/****explicit****/
/*一般用在构造函数中,需要明白/明确调用*/
class PP
{
public:
PP(int a,int b)
{
cout << "p(int a,int b)"<<endl;
}
PP(initializer_list<int>)
{
cout << "initializer_list<int>"<<endl;
}
explicit PP(int a,int b,int c)
{
cout <<"explicit P(int a,int b,int c)"<<endl;
}
};
void fp1(const PP&)
{
}
void test07()
{
PP p1(77,5);
PP p2{77,5};
PP p3{77,5,42};
PP p4= {77,5};
PP p5 = {77,5,42};//这个走了 intializer_list<int> 没有因为 explicit pp(int,int,int)而报错,需要把intializer_list<int>构造取消才会报错
PP p6 (77,5,42);
fp1({77,5});
fp1({77,5,42});//这个走了 intializer_list<int> 没有因为 explicit pp(int,int,int)而报错,需要把intializer_list<int>构造取消才会报错
fp1( PP{77,5} );
fp1( PP{77,5,42});
PP p7 {77,5,42,500};
PP p8 = {77,5,42,50};
PP p9{10};
}
/***explicit end***/
/**** =default =delete ***/
class Zoo
{
public:
Zoo(int i1,int i2):d1(i1),d2(i2){}
Zoo(const Zoo&)=delete;//我不要编译器的默认版本
Zoo(Zoo&&)=default;//我要编译器提供的默认版本
Zoo& operator=(const Zoo&)=delete;
Zoo& operator=(Zoo&&)=default;
virtual ~Zoo(){};
private:
int d1, d2;
};
class Foo
{
public:
Foo(int i):_i(i){}
Foo()=default;
Foo(const Foo& x):_i(x._i){}
//Foo(const Foo& x)=default;cannot be overloaded with 'Foo::Foo(const Foo&)
//Foo(const Foo& x)=delete;
Foo& operator=(const Foo& x){_i = x._i;return *this;}
//Foo& operator=(const Foo& x)=delete;cannot be overloaded with 'Foo& Foo::operator=(const Foo&)'
//Foo& operator=(const Foo& x)=default;cannot be overloaded with 'Foo& Foo::operator=(const Foo&)'
//void func1()=default;
void fun2()=delete;
//~Foo()=delete;use of deleted function 'Foo::~Foo()'
~Foo()=default;
private:
int _i;
};
void test10()
{
Foo f1(5);
Foo f2;
Foo f3(f1);
f3 = f2;
}
/*类中如果有指针,是需要自定义的big-three or big-five的,包括析构
因为存在浅拷贝和深拷贝的问题*/
struct nocopy
{
nocopy(const nocopy&)=delete;
nocopy& operator=(const nocopy&)=delete;
};
struct nodtor
{
~nodtor()=delete;
};
class privatecopy
{
private:
privatecopy(const privatecopy&);
privatecopy& operator=(const privatecopy&);
};
void test11()
{
//nodtor nd1;无法引用 函数 "nodtor::~nodtor() noexcept" (已声明 所在行数:315) -- 它是已删除的函数
nodtor *nd2 = new nodtor();
//delete nd2;无法引用 函数 "nodtor::~nodtor() noexcept" (已声明 所在行数:315) -- 它是已删除的函数
}
/**** =default =delete end**/
/****alias template****/
/**模板化名*************/
template<typename T>
using Vec = vector<T,allocator<T>>;
void test12()
{
Vec<int> coll; // == vector<int,MyAlloc<int>> coll;
}
//思路
//想要实现拥有任意元素类型的任意容器的初始化,同时还有容器的拷贝构造和移动构造,实现容器的基本功能
//第一部 Container 它不是一个模板类型,所以想这是不是整一个参数模板就好了
//结果发现整了参数模板之后呢,编译器会说 351行 Container不是一个模板 template
//--->接着就想说那我把Container改成一个模板typename Container<T> c;
//---->编译器还是会报错 expected nested-name-specifier before "Contaner" ,即会希望有个::
//---->然后接着改
//template<typename Container,typename T>
//void test_moveable(Container cntr,T elem)
// output_static_data(T());
//--->改函数 采用function template + iterator + traits
/*template<typename Container>
void test_moveable(Container cntr)
{
typedef typename iterator_traits<typename Container::iterator>::value_type Valuetype;
for(long i=0;i<SIZE;i++)
c.insert(c.end(),Valuetype());
output_static_data(*(c.begin()));
Container<T>c1(c);
Container<T>c2(move(c)));
c1.swap(c2);
}*/
---->可以用 template template parameter
/*
发现报错
error: type/value mismatch at argument 2 in template parameter list for 'template<class T, template<class> class Container> class XCIs'
390 | XCIs<int,vector> c;
| ^
expected a template of type 'template<class> class Container',
got 'template<class _Tp, class _Alloc> class std::vector'
*/
//---->进行alias template使用
template<typename T>
using Vec1 = vector<T,allocator<T>>;
#define SIZE 100
template<typename T,template<class> class Container>
class XCIs
{
private:
Container<T> c; //Container一定必须是一个模板,才可以用<>;而Container 又是上面那一个的模板参数
public:
XCIs()
{
for(long i=0;i<SIZE;i++)
c.insert(c.end(),T());
//output_static_data(T());
Container<T>c1(c);
Container<T>c2(move(c));
c1.swap(c2);
}
};
void test13()
{
// XCIs<int,Vec> c;
//同步更改
XCIs<int,Vec> c1;
}
/***alias template end**/
/***type alias***/
template<typename T>
struct Contaner1
{
/* data */
using value_type = T;
value_type a;
};
template<typename cnt>
void fn2(const cnt&c)
{
//typename的作用就是告诉编译器,typename后面的字符串为一个类型名称,而不是成员函数或者成员变量
typename cnt::value_type n4;//typename 表示作用域再cnt里的value_type定义的一个参数 n4
n4 = c.a;//n4 等于 传进来的 a
cout << n4 << endl;
}
void testaliastype()
{
Contaner1<int> cnt;
cnt.a = 1;
fn2(cnt);
}
/***type alias end**/
/**C++11新特性关键字**/
/***noexcept***/
/*在函数后面加上noexcept,表示函数不会丢出异常
void foo()noexcept;-
-->void foo()noexcept(true); //还可以加上小括号表示哪种情况不丢异常
void swap(Type& x,Type& y)noexcept(noexcept(x.swap(y)))
{
x.swap(y)
}*/
//vector,deque是growable conatiners会发生memory reallocation
//它要用的类的move constructor和move assignment必须是noexcept的
class MyString{
private:
char* _data;
size_t _len;
public:
//move constructor
MyString(MyString&& str)noexcept
:_data(str._data),_len(str._len){}
//move assignment
MyString& operator=(MyString&& str)noexcept{return *this;}
};
/**noexcept end**/
/**override 关键字 在子类实例化虚函数的时候加上override,可以让编译器帮助在编译时审核***/
struct Base
{
virtual void vfunc(float){}
};
struct Derived1:Base{
//使用“override”声明的成员函数不能重写基类成员
//virtual void vfunc(int)override{}
virtual void vfunc(float)override{}
};
/**override end***/
/**final***/
struct Base2 final{};
//不能将“final”类类型用作基类
//struct Derived2:Base2{};
struct Base3{virtual void f() final;};
//无法重写“final”函数 "Base3::f" (已声明 所在行数:481)
//struct Derived3:Base3{void f();}
//无法重写“final”函数 "Base3::f" (已声明 所在行数:481)
//struct Derived3:Base3{virtual void f() override{}}
/**final end**/
/**decltype*****/
/*
by using the new decltype keyword,you can let compiler findout the type of an expression.
map<string,float>coll;
//通过对象可以知道类型
decltype(coll)::value_type elem; === map<string,fload>::value_type elem;
//应用
1 declare return types
2 in metaprogramming
3 pass the type of a lambda
*/
//1.declare return types
//template<typename T1,typename T2>
//decltype(x+y)add(T1 x,T2 y);
//add的返回类型是x+y之后的返回类型
template<typename T1,typename T2>
auto add(T1 x,T2 y)->decltype(x+y);//新的函数类型返回方式auto f()->有点像lambdas
//2.in metaprogramming
template<typename T>
void test18_decltype(T obj)
{
//map<string,float>::value_type elem1;
//map<string,float>coll;
//decltype(coll)::value_type elem2;
//2 如今有了dectype我可以
typedef typename decltype(obj)::iterator iType; //只要加上::就要加上typename 所以itype就成了这个obj容器迭代器的名称
for(iType i = obj.begin();i!=obj.end();i++)
{
cout << *i << endl;
}
}
void test18()
{
//test18_decltype(complex<int>());
//error: no type named 'iterator' in 'struct std::complex<int>'
test18_decltype(vector<int>{1,2,3,4});
}
//3.pass the type of a lambda
//cmp 对象
//cmp 对象类型是什么类
//不知道,那如果需要调用cmp的类型怎么办呢,就需要用dectype
//比如在set容器里
//面对lambda,我们手上往往只有object,没有type.
// auto cmp = [](const Person& p1,const Person& p2){
// return p1.lastname()<p2.lastname()||
// (p1.lastname() == p2.lastname()&&
// p1.firstname()<p2.firstname());
// };
// std::set<Person,dectype(cmp)>coll(cmp);
//dectype(cmp) lambda set的排序准则
//所以需要把lambda对象传给coll,否则coll会按照set的默认构造中的set():t(Compare()){} 中的Compare(),也就是lanmbda的默认构造函数
//但是lambda没有默认构造函数也没有赋值操作,所以就会报错
//所以作为一个排序准则可能用仿函数或者比较好
/**decltype end***/
/***************lambda************/
/*
the definition of inline functionality can be used as
a parameter or a local object.
you can defined inside statements and expressions.
比如sort我们指定降序排序时,写仿函数或者函数对象,现在可以用lambda
lambda的格式:
[]开头的
比如:
[]{
cout<<"hello lambda"<<endl;
} 可以看成一个函数对象,用()可以调用哦
要调用的话呢要改成
[]{
cout<<"hello lambda"<<endl;
} ();
或者携程
auto l = []{
cout<<"hello lambda"<<endl;
};
...
l(); //可以看成一个函数对象,用()可以调用哦
语法的完整形式
[...](...)mutable throwSpec ->retType {}
取用 参数 关键字 异常处理 返回类型
外部
变量
[=]by value
[&]by reference
*/
void testlambda()
{
int id = 0;
auto f = [id]()mutable{
cout << "id: "<<id << endl;
++id;
};//mutable不加,id就无法++。
/*类于如下:这个id在编译的时候已经定了,就是0;跟后面那个不是同一个,这个id是这个lambda自身已经编译时就赋值好了
class Functor{
private:
int id;
public:
void operator(){
cout << "id: "<<id << endl;
++id;
}
};
Functor f;
*/
id=42;
f();//0
f();//1
f();//2
cout << id << endl;
}
void testlambda2()
{
int id = 0;
auto f = [&id](int param){
cout << "id:"<<id<<endl;
++id;
++param;
};//by reference 内外互相影响
id = 42;
f(7);
f(7);
f(7);
cout << id << endl;
}
void testlambda3()
{
int id = 0;
auto f = [id](){
cout << "id:"<<id<<endl;
// ++id;//表达式必须是可修改的左值
};
id = 42;
f();
f();
f();
cout << id << endl;
}
void testlambda4()
{
int id = 0;
auto f = [id]()mutable{
cout << "id:"<<id<<endl;
++id;
static int x=5; //可以声明变量,也可以返回数值
int y=6;
return id;
};
id = 42;
f();
f();
f();
cout << id << endl;
}
void testlambda5()
{
vector<int>vi {5,28,50,83,70,590,245,59,24};
int x = 30;
int y = 100;
vi.erase(remove_if(vi.begin(),vi.end(),[x,y](int n){return x<n&&n<y;}),vi.end());
for(auto i:vi)
cout << i <<" ";
cout << endl;
}
/***************lambda end********/
/*****C++11新特性 关键字 结束*****/
int main()
{
/*cout << __cplusplus << endl;
print(7.5,"hello",bitset<16>(377),42); //编译器优先调用特化的
tuple<int,float,string> t(41,6.3,"nico");
vector<list<int>> v1;//可以 <list<>> 不需要<list<> >*/
//test03();
//test05();
//test06();
//test07();
//test08();
//testaliastype();
testcomptuple();
system("pause");
return 0;
}
侯捷先生的C++2.0新特性--PART1
最新推荐文章于 2022-06-09 12:47:13 发布