若类重载了函数调用运算符(),就可以像使用函数一样使用该类的对象(像函数调用一样来调用该类的对象)。
class biggerthanzero {
public:int operator()(int value) const {if(value<0)return 0;return value;}
};int i = 200;
biggerthanzero obj;
int result = obj(i); //等价于int result = obj.operator()(i);
class biggerthanzero {
public:biggerthanzero(int i) {cout<<"biggerthanzero::biggerthanzero(int)\n";}int operator()(int value) const {if(value<0)return 0;return value;}
};int i = 200;
biggerthanzero obj(i);//对象定义并初始化,调用的是biggerthanzero构造函数
int result = obj(i); //等价于int result = obj.operator()(i);
若类重载了()运算符(可有多个版本,参数类型或数量有差别即可),则类对象就变成了可调用对象(函数对象)。
int echovalue(int value) {cout<
echovalue函数和biggerthanzero类重载的函数调用符具有相同的形参和返回值,叫做调用形式相同。
一种调用形式对应一个函数类型。
int(int)表示接收一个int参数,返回一个int值的函数类型。
可以将可调用对象(函数对象、仿函数)的指针保存起来,方便后续随时调用。
map myoper;
myoper.insert({"ev", echovalue});//系统不会将类biggerthanzero或类对象obj看成函数指针
biggerthanzero obj;
myoper.insert({"bt", biggerthanzero});//error
myoper.insert({"bt", obj}); //error
function,类模板,用来包装可调用对象,统一了类型。
biggerthanzero obj;
function f1 = echovalue;
function f2 = obj;
function f3 = biggerthanzero();f1(5);
f2(3);
f3(-5);
biggerthanzero obj;
map> myoper = {{"ev", echovalue},{"bt", obj}
};
myoper.insert({"bt2", biggerthanzero()});myoper["ev"](12);
myoper["bt"](3);
myoper["bt2"](-5);
只要函数是重载的,就无法包装进function中。
可以通过定义函数指针解决。
int echovalue(int value) {cout<return;
}function f1 = echovalue; //errorint(*fp)(int) = echovalue;
function f1 = fp; //ok
void func(const int&abc){}
//abc类型为const int&
template
void func(const T&abc){}func(10);
//T(类型模板参数)的类型是int(与输入参数10和abc类型即const int &有关)
//abc(变量)的类型是const int &
universal reference(forwarding reference,转发引用),万能引用(未定义引用)。
万能引用是一种类型。
void func(int &&tmp) {//tmp为右值引用类型cout<
//函数模板推断+函数形参为T&&会出现万能引用
//auto && tmp = ...也是万能引用
//实参传递左值,则万能引用是左值引用(tmp被推断为int &类型,假设传递int)
//实参传递右值,则万能引用是右值引用(tmp被推断为int &&类型,假设传递int)
//T&&(tmp)是万能引用,T不是
template
void func(T&& tmp){//tmp类型为T&&,&&和T类型无关cout<
void func(int &¶m){}//右值引用template
void func(T&& tmp){} //万能引用template
void func(vector&& tmp){} //右值引用
template
void myfunc(T&& tmp){tmp = 12;cout<
//const剥夺万能引用资格,const T&&只能是右值引用。
template
void myfunc(const T&& tmp){//右值引用tmp = 12;cout<
template
class mytestc {
public:void testfunc(T&& x){}//右值引用,不是万能引用
};mytestc mc;
int i = 100;
mc.testfunc(i); //error
mc.testfunc(std::move(i)); //ok
template
class mytestc {
public:void testfunc(T&& x){}//右值引用,不是万能引用templatevoid testfunc2(T2&& x){}//万能引用
};mytestc mc;
int i = 100;
mc.testfunc2(i); //ok
mc.testfunc2(std::move(i)); //ok
boost
#include template
void myfunc(T& tmprv){using boost::typeindex::type_id_with_cvr;cout<<"T = "<().pretty_name()<().pretty_name()<
#include template
void myfunc(const T& tmprv){using boost::typeindex::type_id_with_cvr;cout<<"T = "<().pretty_name()<().pretty_name()<
#include template
void myfunc(T& tmprv){using boost::typeindex::type_id_with_cvr;cout<<"T = "<().pretty_name()<().pretty_name()<
#include template
void myfunc(const T& tmprv){using boost::typeindex::type_id_with_cvr;cout<<"T = "<().pretty_name()<().pretty_name()<
#include template
void myfunc(T* tmprv){using boost::typeindex::type_id_with_cvr;cout<<"T = "<().pretty_name()<().pretty_name()<
template
void myfunc(T&& tmprv){...}int i = 18;
myfunc(i);
//T = int &
//tmprv = int &const int j = i;
myfunc(j);
//T = int const &
//tmprv = int const &const int& k = i;
myfunc(k);
//T = int const &
//tmprv = int const &myfunc(100);
//T = int
//tmprv = int &&
template
void myfunc(T tmprv){...}int i = 18;
myfunc(i);
//T = int
//tmprv = intconst int j = i;
myfunc(j);
//T = int
//tmprv = intconst int& k = i;
myfunc(k);
//T = int
//tmprv = intchar mystr[] = "test";
const char * const point = mystr;
myfunc(point);
//myfunc(mystr);//同上
//T = char const *
//tmprv = char const *
//tmprv = nullptr;//ok
//*tmprv = 'Y';//error
template
void myfunc(T tmprv){...}const char mystr[] = "test";
myfunc(mystr);
//T = char const *
//tmprv = char const *
template
void myfunc(T& tmprv){...}const char mystr[] = "test";
myfunc(mystr);
//T = char const [5]
//tmprv = char const (&)[5]
template
void myfunc(T (&tmprv)[L1]){...}const char mystr[] = "test";
myfunc(mystr);
//T = char const [5]
//tmprv = char const (&)[5]
template
void myfunc(T tmprv){...}void testFunc(){}myfunc(testFunc);
//T = void(__cdecl *)(void)
//tmprv = void(__cdecl *)(void)
template
void myfunc(T& tmprv){...}void testFunc(){}myfunc(testFunc);
//T = void __cdecl (void)
//tmprv = void(__cdecl &)(void)
template
void myfunc(T&& tmprv){...}int i = 18;
myfunc(i);
//T = int &
//tmprv = int &myfunc(100);
//T = int
//tmprv = int &&
//第一组&是左值引用,第二组&&是右值引用
//左值相遇、左右值相遇、右值相遇、右左值相遇,会发生&符合的合并,折叠。
void myfunc(int& && tmprv){...}int i = 18;
myfunc(i);
//tmprv = int &
//第一组&是左值引用,第二组&&是右值引用
//左值相遇、左右值相遇、右值相遇、右左值相遇,会发生&符合的合并,折叠。
void myfunc(int& && tmprv){...}//编译器内部进行折叠(合并),程序不能写三个&&&
//int b = 500;
int& byi = b;
//int& &byy = byi;//error
//int& &byy2 = b;//error左值-左值,&-&
左值-右值,&-&&
右值-左值,&&-&
右值-右值,&&-&&
存在左值引用,结果就是左值引用。上述组合结果为:
左值引用,&
左值引用,&
左值引用,&
右值引用,&&
转发,把收到的参数以及这些参数相对应的类型(const、左值、右值等)不变地转发给其他函数的函数模板。
万能引用T&&函数模板的形参,可以保存实参的所有类型信息(const、引用等),编译器据此推断出函数模板最终的形参类型。
template
void myFuncTemp(F f, T1 &&t1, T2 &&t2){...}
//实参中来的左值或者右值信息、const信息都保存在t1和t2参数中
void myfunc(int v1, int& v2){++v2;cout<cout<}int j = 2;
//20右值,j左值
myFuncTemp(myfunc2, 20, j);template
void myFuncTemp(F f, T1 &&t1, T2 &&t2){f(t1, t2);//t1,t2都是左值(变量,形参本身是左值),即使t1是右值引用
}//v1中v1需要右值,myfunc2传递左值会报错
void myfunc2(int&& v1, int& v2){cout<
专门为转发而存在的函数,要么返回左值,要么返回右值。
实参左值,std::forward后还是左值;
实参右值,形参变为左值,std::forward后转为右值。
std::forward能够保持原始实参的左值或者右值性。
void printInfo(int& t){cout<<"int&"<cout<<"int&&"<
void testF(T&& t){using boost::typeindex::type_id_with_cvr;cout<<"T = "<().pretty_name()<().pretty_name()<(t));printInfo(std::move(t));
}TestF(1);
/*
T = int
t = int &&
int&
int&&
int&&
*/int i = 1;
TestF(i);
/*
T = int &
t = int &
int&
int&
int&&
*/
int ix = 12;
//std::forward(ix)转为右值
//std::forward(ix)转为左值
int&& def = std::forward(ix);
完美转发,将任意的函数名、任意类型参数(个数确定)(保持参数类型不变)传递给函数模板,达到间接调用函数的目的。
声明变量时根据变量初始值的类型自动推断匹配类型。
auto特点:
//auto理解为类型模板参数T,x理解为模板中形参类型。
//T(auto) = int
//tmprv(x) = int
auto x = 27;
auto x = 27;//T = int, t = int
const auto x2 = x;//T = int, t = const int
const auto& xy = x;//T = int, t = const int&
auto xy2 = xy;//T = int, t = int
传值方式针对auto类型会抛弃引用、const等限定符。
auto x = 27;
const auto& xy = x;//const int&auto& xy3 = xy;//const int &, auto = const int
auto y = new auto(100); // y = int*, auto = int *,auto可用于new操作符const auto* xp = &x;//const int *, auto = int
auto * xp2 = &x; //int *, auto = int
auto xp3 = &x;// int *,
auto x = 22;
auto&& wnyy0 = 222;//int&&, auto = int
auto&& wnyy1 = x;//int&, auto = int&const auto x2 = x;//const int
auto&& wnyy3 = x2;//int const &, auto = int const &
const char mystr[] = "test";//const char[5]
auto myarr = mystr;//char const *
auto& myarr2 = mystr;//char const(&)[5]int a[2] = {1, 2};
auto aauto = a;// int *
void myfunc3(double, int){cout<<"myfunc3"<
初始化变量方法:
int x = 10;//c++98
int x2(20);//c++98
int x3 = {30};//c++11
int x4{40};//c++11
auto x = 10;//int
auto x2(20);//c++98
auto x3 = {30};//std::initializer_list,隐式类型转换
auto x4{40};//int
std::initializer_list是c++1中类模板,数组,与vector类型。
auto x5 = {30, 21};
auto x6 = {30, 21, 45.3};//error,类型不一致
template
void fautof(T param){}fautof({12});//error
template
void fautof(std::initializer_list param){}fautof({12});//ok
//c++14支持
auto funca(){return 12;
}
(1)不能用于函数参数。
void myfunc(auto x, int y){}//error
(2)不能类中普通成员变量。
class CT{
public://auto m_i = 12;//errorstatic const auto m_si = 15;//ok
};
std::map mymap;
mymap.insert({"aa", 1});
mymap.insert({"bb", 2});
mymap.insert({"cc", 3});
mymap.insert({"dd", 4});//for(std::map::iterator iter = mymap.begin(); iter != mymap.end(); ++iter)
for(auto iter = mymap.begin(); iter != mymap.end(); ++iter)cout<first<<" = "<second<
class A{
public:static int testr(){return 0;}
};class B{
public:static double testr(){return 10.5;}
};template
auto ftestclass(){auto value = T::testr();return value;
}cout<()<()<
decltype用于推导表达式或者变量名的类型,与auto类型。
decltype特点:
const int i = 0;
const int& iy = i;
auto j1 = i;//传值方式推断,引用、const等被抛弃,int
decltype(i) j2 = 15;//const int
decltype(iy) j3 = j2;//const int &
class CT{
public:int i;int j;
};decltype(CT::i) a;//int
CT tmpct;
decltype(tmpct) tmpct2;//CT
decltype(tmpct2.i) mv = 5;//int
int x = 1;
auto&& z = x;//万能引用,x左值,auto是int&,z也是int&
int y = 2;
decltype(z) &&h = y;//int & &&,折叠引用,最终int &h = y;
decltype(8) kkk = 5;//intint i = 0;
decltype(i) k2;//intint *pi = &i;
decltype(pi) k;//int *
*pi = 4;
//*pi是左值,*pi是表达式不是变量
//如果表达的结果能够作为赋值语句等号左侧的值(*pi=4;)
//那么decltype后返回的就是一个引用
decltype(*pi) k3 = i;//int &
//(i)表达式,i左值
//decltype((变量))的结果永远是引用
decltype((i)) iy3 = i;//int &int& iy = i;
decltype(iy+1) j;//int
int testf(){return 10;
}decltype(testf()) tmpv = 14;//int
decltype(testf) tmpv2;//int(void),可调用对象function ftmp = testf;
cout<return 0;
}decltype(myfunctest()) myy = 0;//const int &&
template
class CTTMP{
public:typename T::iterator iter;void getbegin(T &tmpc){iter = tmpc.begin();}
};using conttype = std::vector;
conttype myarr = {10, 30, 40};
CTTMP ct;
ct.getbegin(myarr);
//using conttype = const std::vector;//error,
常量容器定义初始化,begin等返回常量迭代器vector::const_iterator,而不是vector::iterator
c++98通过写类模板偏特化解决
template
class CTTMP{
public:typename T::const_iterator iter;void getbegin(const T &tmpc){iter = tmpc.begin();}
};
template
class CTTMP{
public:decltype(T().begin()) iter;void getbegin(T &tmpc){iter = tmpc.begin();}
};
class A{
public:A(){cout<<"A()"<cout<<"~A()"<cout<<"func()"<
vector ac;
ac.push_back(1);
ac.push_back(2);vector::size_type mysize = ac.size();
cout<
auto func(int a, int b) -> int{}
auto add(int i, int k) -> decltype(i+k) {return i + k ;
}
int& tf(int& i){return i;
}
double tf(double& d){return d;
}template
auto FuncTmp(T& tv) -> decltype(tf(tv)) {return tf(tv);
}int i = 19;
cout<
(1)函数返回类型
template
T& mydouble(T& v){v *= 2;return v;
}
int a = 100;
mydouble(a) = 20;
cout<
template
auto mydouble(T& v){//auto推导去掉引用v *= 2;return v;
}
template
decltype(auto) mydouble(T& v){//保留引用v *= 2;return v;
}int a = 100;
decltype(mydouble(a)) b = a;//int &
(2)变量声明
int x = 1;
const int& y = 1;
auto z = y;//int
decltype(auto) z2 = y;//z2与y完全一致, const int&
(3)(变量)
int i = 10;
decltype((i)) iy3 = i;//int &
decltype(auto) tf1(){int i = 1;return i;//int
}
decltype(auto) tf2(){int i = 1;return(i);//int&
}decltype(tf1()) testa = 4;//int
int a = 1;
decltype(tf2()) testb = a;//int&
tf2() = 12;//引用值已释放
void myfunc(int tv){cout<
class TC{
public:void operator()(int tv){cout<
class TC2{
public:using tfpoint = void(*)(int);static void mysfunc(int tv){cout<return mysfunc;}//类型转换运算符/函数
};TC2 tc2;
//先调用tfpoint,再调用mysfunc,这就是一个可调用对象,等价于tc2.operator TC2::tfpoint()(20);
tc2(20);
class TC{
public:void ptfunc(int tv){cout<
可调用(可使用函数运算符“()”)对象,可以类似a(参数1,参数2,…)使用。
可调用对象调用形式统一(名字(参数列表)),定义方法不同。
std::function将可调用对象包装起来,统一可调用对象的调用形式。
void func(int v){cout< f = func;
func(10);
class TC{
public:static void func(int v){cout< f = TC::func;
f(10);
class TC{
public:void operator()(int v){cout< f = tc;
f(10);
void mycallback(int cs, const std::function &f){f(cs);
}void runfunc(int x){cout<
#include
#include
using namespace std;class CB
{std::function fcallback;public:~CB(){cout << "CB:~CB()" << endl;}CB(const std::function &f) : fcallback(f){cout << "CB:CB(const std::function &)" << endl;}void runcallback(){fcallback();}
};class CT
{
public:~CT(){cout << "CT:~CT()" << endl;}CT(){cout << "CT:CT()" << endl;}CT(const CT &){cout << "CT::(const CT &)" << endl;}void operator()(){cout << "CT::operator()()" << endl;}
};int main()
{if (0){CT ct;const std::function &f = ct; //CT::(const CT &)std::function fcallback = f ; //CT::(const CT &)}if (1){CT ct;CB cb(ct);cb.runcallback();}cout << "Over!" << endl;return 0;
}
std::bind是函数模板,取代c++98中的bind1st和bind2nd。
std::bind将对象及相关参数绑定在一起,绑定完后可以直接使用,也可以用std::function保存,需要时调用。
std::bind(待绑定的函数对象/函数指针/成员函数指针,参数绑定值1,参数绑定值2,...,参数绑定值n)
std::bind两层意思:
void myfunc1(int x, int y, int z){cout<<"x="<
void myfunc2(int& x, int& y){x++;y += 2;
}int a = 2;
int b = 3;
//bind预先绑定的参数通过值传递,a值传递
//不事先绑定的参数,placeholders通过引用传递,b引用传递
auto bf4 = std::bind(myfunc2, a, placeholders::_1);
bf4(b);//
cout<
class CQ{
public:void myfunc(int x, int y){m_a = x;}int m_a = 0;
};CQ cq;
//cq会生成临时CQ对象
//&cq不会生成临时CQ对象
auto bf5 = std::bind(&CQ::myfunc, cq, placeholders::_1, placeholders::_2);
bf5(10, 20);std::function bf6 = std::bind(&CQ::myfunc, &cq, placeholders::_1, placeholders::_2);
bf6(10, 20);
class CQ{
public:CQ(){cout<<"CQ(): "<cout<<"CQ(const CQ&): "<cout<<"~CQ(): "< bf7 = std::bind(&CQ::m_a, &cq);
bf7() = 7;//cq.m_a = 7//std::function bf7 = std::bind(&CQ::m_a, cq);
//会调用两次拷贝构造函数,两次析构函数
//一次cq生成临时对象
//一次bind要返回包装后的CQ对象//会调用一次构造函数,一次拷贝构造函数,两次析构函数
auto rt = std::bind(CT());
rt();
void mycallback(int cs, const std::function &f){f(cs);
}void runfunc(int x){cout<
lambda表达式也是一种可调用对象,定义一个匿名函数,并且可以捕获一定范围内的变量。
//lambda表达式一般形式:
//[捕获列表](参数列表) -> 返回类型{函数体;};
auto f = [](int a) -> int {return a + 1;
};
cout <
lambda表达式特点:
注意:
(1)返回类型后置或者省略(return语句推断返回值类型)。
(2)参数列表可以有默认值。
auto f = [](int a = 8) -> int {return a + 1;
};
(3)无参时,参数列表甚至’()'都可以省略。
auto f1 = [](){return 1;
};
auto f2 = []{return 1;
};
(4)捕获列表[]和函数体{}不能省略。
捕获列表捕获一定范围内的变量。
(1)[]:不捕获任何变量。
int i = 9;
auto f = []{return i;//error,无法捕获外部变量i
};
static int i = 9;
auto f = []{return i;//ok,可以直接使用局部静态变量
};
(2)[&]:捕获外部作用域中所有变量,作为引用在函数体中使用。
int i = 9;
auto f = [&]{i = 5; //&,会修改i值return i;
};
(3)[=]:捕获外部作用域中所有变量,作为副本(按值)在函数体中使用,可以使用,不能赋值(常量引用?)。
int i = 9;
auto f = [=]{//i = 5; //error,不能赋值return i;
};
(4)[this]:用于类中,捕获当前类this指针,让lanbda表达式拥有和当前类成员函数同样的访问权限。使用"&“和”="时,默认添加了此项“this”。
[this]和[=]可以读取,不能修改;[&]可以修改。
class CT{
public:int m_i = 5;void myfuncpt(int x, int y){auto mylambda = [this] {//this,&,=都可以读取成员变量值return m_i;};cout<
(5)按值捕获和按引用捕获。
class CT{
public:int m_i = 5;void myfuncpt(int x, int y){auto mylambda1 = [this] {return m_i;};//不能使用x,yauto mylambda2 = [=] {return m_i;};//能使用x,y,不能修改auto mylambda3 = [&] {return m_i;};//能使用x,y,能修改auto mylambda4 = [this, x, y] {return m_i;};//能使用x,y,不能修改auto mylambda5 = [&x, &y] {return x;};//能使用x,y,能修改}
};
(6)[=, &变量名]:默认按值捕获所有外部变量,其他变量按引用捕获,多个变量逗号隔开。
auto mylambda = [this, &x, y] {return m_i;};
//或者
auto mylambda = [=, &x] {return m_i;};
(7)[&, 变量名]:默认按引用捕获所有外部变量,其他变量按值捕获,多个变量逗号隔开。
auto mylambda = [&, x] {...};
int x = 5;
auto f = [=] {return x;};//5
x = 10;
cout<
lambda捕获的时刻,已经复制x的值了。
lambda捕获时,已经将所有外部变量值复制一份存储在了lambda表达式变量中。
&引用可以及时访问外部值。
int x = 5;
auto f = [=]() mutable{x = 6; //无mutable时x不能修改return x;
}
x = 10;
cout<
//存在mutable时,即使无参数,()也不能省略
auto f = [=]() mutable{x = 6; //无mutable时x不能修改return x;
}
lambda表达式的类型称为闭包类型(CLosure Type),闭包:函数内的函数(可调用对象)。
捕获到的外部变量可看作闭包类型的成员变量,这些成员变量在lambda对象创建时被初始化。
auto aa = [](){};
auto bb = [](){};
using boost::typeindex::type_id_with_cvr;
cout<<"aa="<().pretty_name()<().pretty_name()<};//f是一个匿名的类类型对象
std::function fc1 = [](int tv){return tv};
fc1(15);//15//bind中,第一个参数是函数指针
//第二个参数是tv
std::function fc2 = std::bind([](int tv){return tv}, 16);
//bind绑定死tv为16,这里参数15不起作用,除非bind中使用placeholders::_1
//std::bind([](int tv){return tv}, placeholders::_1);
fc2(15);//16
不捕获任何变量的lambda表达式,可转换为普通的函数指针。
using functype = int(*)(int);
functype fp = [](int tv){return tv};
cout<
语法糖是指基于语言现有的特性,构建出一个东西,程序员用起来会很方便。但它没有增加语言的原有功能。lambda表达式可看成定义仿函数闭包(函数中的函数)的语法糖。
vector myvector = {10, 20, 30, 40, 50};
int sum = 0;
for_each(myvector.begin(), myvector.end(), [&sum](int val){sum += val;cout<
vector myvector = {10, 20, 30, 40, 50};
auto result = find_if(myvector.begin(), myvector.end(), [](int val){cout<
vector myvector = {10, 20, 30, 40, 50};
auto result = find_if(myvector.begin(), myvector.end(), [](int val){if(val>15)return true;return false;//返回false,find_if会不停遍历myvector,直到返回true
});if(result == myvector.end())cout<<"not find"<
lambda表达式优点:代码简洁、灵活、强大,提高开发效率、可维护性等。
引用捕获会导致lambda表达式(闭包)包含绑定到局部变量的引用。
#include
std::vector> gv;void myfunc(){srand((unsigned)time(NULL));int tmpvalue = rand() % 6;gv.push_back([&](int tv){return tv % tmpvalue == 0;//tmpvalue局部变量,引用悬空});
}myfunc();
cout<
c++14允许lambda的形参列表使用auto
gv.push_back([=](auto tv){return tv % tmpvalue == 0;//tmpvalue会复制一份});
class AT{
public:void addItm(){gv.push_back([=](auto tv){//=实际等于thisreturn tv % tmpvalue == 0;//tmpvalue实际是this->tmpvalue, 不会复制一份});}int tmpvalue = 7;
};AT *pat = new AT();
pat->addItem();
delete pat;
cout<
void addItm(){auto tmpvalueCopy = tmpvalue;gv.push_back([tmpvalueCopy](auto tv){return tv % tmpvalueCopy == 0;//tmpvalueCopy赋值, 不是类AT的成员变量});}
void addItm(){gv.push_back([tmpvalueCopy = tmpvalue](auto tv){//tmpvalue复制到闭包里来return tv % tmpvalueCopy == 0;});}
静态局部变量不能被捕获,但能在lambda表达式中使用。
void myfunc(){static int tmpvalue;srand((unsigned)time(NULL));tmpvalue = rand() % 6;gv.push_back([](auto tv){//[],static不需要捕获return tv % tmpvalue == 0;});
}
void myfunc(){static int tmpvalue = 4;gv.push_back([](auto tv){//[],static不需要捕获cout<
initializer_list处理非固定参数,但类型相同。
参数数量不固定,参数类型相同。
initializer_list中元素是常值,不能被改变。
initializer_list myarray;
initializer_list myarray2 = {12, 14, 16, 20, 30};
void printvalue(initializer_list tmpstr){for(auto beg = tmpstr.begin(); beg != tmpstr.end(); ++beg)cout<c_str()< tmpstr){for(auto& tmpitem : tmpstr)cout<"aa", "bb", "cc"});void printvalue(initializer_list tmpstr, int tmpvalue){...}
printvalue({"aa", "bb", "cc"}, 6);
initializer_list myarray3 = {"aa", "bb", "cc"};
initializer_list myarray4(myarray3);
initializer_list myarray5;
myarray5 = myarray4;
class CT{
public:CT(initializer_list &tmpvalue){}
};CT ct1 = {10, 220, 30, 40}; //隐式类型转换,explicit可禁止
CT ct2{10, 220, 30, 40};
CT ct3 = CT({10, 220, 30, 40});
int myarray[] = {1, 5, 6, 9};
int myarray2[]{1, 5, 6, 9};
vector myvec = {1, 5, 6, 9};
编译器看到大括号括起来的形如{“aa”, “bb”, “cc”}的内容,一般会转化为std::initializer_list。
可变参数函数必须至少有一个普通参数。
#include double average(int num, ...){va_list valist;double sum = 0;va_start(valist, num);for(int i=0; i
void funcTest(const char *msg...){int csgs = atoi(msg);va_list valist;va_start(valist, msg);for(int paramcount = 0; paramcount < csgs; paramcount++) {char *p = va_arg(valist, char*);printf("%d: %s\n", paramcount, p);}va_end(valist);
}
注意点:
(1)至少一个有效形参;
(2)省略号形参只能出现在最后的位置;
void myfunc(参数列表, ...);
编译器会对参数列表进行类型检查,函数调用时,省略号对应实参不会进行类型检查。
(3)省略号前逗号可以省略;
void funcTest(const char *msg, ...);
void funcTest(const char *msg...);
(4)多个非可变参时,va_start(valist, msg)绑…前那个形参;
void testFunc(char *pszDest, int DestLen, const char *pszFormat...){}
va_start(valist, pszFormat);
type traits,萃取技术一种可用于编译器根据类型作判断的泛型编程技术。
类型萃取定义了一个编译期间的基于模板的接口,用来查询或者修改类型的属性,可以根据这些类型萃取接口来获取各种信息。
(1)主要类型种类
is_void
is_null_pointer
is_integral
is_floating_point
is_array
is_enum
is_union
is_class
is_function
is_pointer
is_lvalue_reference
is_rvalue_reference
is_member_object_pointer
is_member_function_pointer
(2)复合类型种类
is_fundamental
is_arithmetic
is_scalar
is_object
is_compound
is_reference
is_member_pointer
(3)类型属性
is_const
is_volatile
is_trivial
is_trivially_copyable
is_standard_layout
is_pod
is_literal_type
has_unique_object_representations
is_empty
is_polymorphic
is_abstract
is_final
is_aggregate
is_signed
is_unsigned
is_bounded_array
is_unbounded_array
(4)支持的操作
trivially(平淡的,可有可无的)信息,若构造函数无初始化,就属于trivially。
is_constructible
is_trivially_constructible
is_nothrow_constructibleis_default_constructible
is_trivially_default_constructible
is_nothrow_default_constructibleis_copy_constructible
is_trivially_copy_constructible
is_nothrow_copy_constructibleis_move_constructible
is_trivially_move_constructible
is_nothrow_move_constructibleis_assignable
is_trivially_assignable
is_nothrow_assignableis_copy_assignable
is_trivially_copy_assignable
is_nothrow_copy_assignableis_move_assignable
is_trivially_move_assignable
is_nothrow_move_assignableis_destructible
is_trivially_destructible
is_nothrow_destructiblehas_virtual_destructoris_swappable_with
is_swappable
is_nothrow_swappable_with
is_nothrow_swappable
template
void printTraitsInfo(const T& t){cout<<"type name: "<::value<::value<::value<::value<::value<::value<::value<::value<::value<::value<::value<
public:A() = default;A(A&& ta) = delete;A(const A& ta) = delete;virtual ~A(){}
};class B{
public:int m_i;int m_j;
};class C{
public:C(int t){}
};printTraitsInfo(int());
printTraitsInfo(string());
printTraitsInfo(A());
printTraitsInfo(B());
printTraitsInfo(C());
printTraitsInfo(list());