C++ 11/14 2
2017-05-21 09:52
183 查看
关键字 =delete,=default,using, noexcept, override, final, decltype,
lambda 函数
variadic template parameter
补充 1.make语法,2.swap, 3.exception,4.set 实现,5.remove_if meta programming. 6.虚继承,7.多继承,8.memcpy(),memset(),memcmp()9. 模版内模版
=delete 可以用在函数提上表示禁止重载某一类函数
可以用来指定禁止某类模版偏特化
参考:
之前的实现形式时将该方法或特化声明在private中但不实现。
想使某一类class不自动产生 拷贝构造,拷贝赋值,可以定义一个uncopyable class 将其 拷贝构造,拷贝赋值放在private中可以避免其子类实现默认或非默认拷贝构造,拷贝赋值构造函数。
http://www.cnblogs.com/xinxue/p/5503836.html
2. using
使用 using 别名后不能特化也不能偏特化
1.typedefs don’t support templatization, but alias declarations do.
2.Alias templates avoid the “::type” suffix and, in templates, the “typename” prefix often required to refer to typedefs.
3.C++14 offers alias templates for all the C++11 type traits transformations.
参考:
https://zhuanlan.zhihu.com/p/21264013
3.noexcept
从语法上讲,noexcept修饰符有两种形式,一种就是简单地在函数声明后加上noexcept关键字。比如:
void excpt_func() noexcept;
另外一种则可以接受一个常量表达式作为参数,如下所示:
void excpt_func() noexcept (常量表达式);
常量表达式的结果会被转换成一个bool类型的值。该值为true,表示函数不会抛出异常,反之,则有可能抛出异常。这里,不带常量表达式的noexcept相当于声明了noexcept(true),即不会抛出异常。
noexcept形如其名地,表示其修饰的函数不会抛出异常。不过与throw()动态异常声明不同的是,在C++11中如果noexcept修饰的函数抛出了异常,编译器可以选择直接调用std::terminate()函数来终止程序的运行,这比基于异常机制的throw()在效率上会高一些。这是因为异常机制会带来一些额外开销,比如函数抛出异常,会导致函数栈被依次地展开(unwind),并依帧调用在本帧中已构造的自动变量的析构函数等。
BlockThrow() 会直接 terminate不会被catch
而noexcept作为一个操作符时,通常可以用于模板。比如:
这里,fun函数是否是一个noexcept的函数,将由T()表达式是否会抛出异常所决定。这里的第二个noexcept就是一个noexcept操作符。当其参数是一个有可能抛出异常的表达式的时候,其返回值为false,反之为true(实际noexcept参数返回false还包括一些情况,这里就不展开讲了)。这样一来,我们就可以使模板函数根据条件实现noexcept修饰的版本或无noexcept修饰的版本。从泛型编程的角度看来,这样的设计保证了关于“函数是否抛出异常”这样的问题可以通过表达式进行推导。因此这也可以视作C++11为了更好地支持泛型编程而引入的特性。
比如在C++98中,存在着使用throw()来声明不抛出异常的函数。
特别的 you need inform C++(specially std::vector,deque)that your move constructor and destructor does not throw. Then the move constructor will be called when vector grows. if the constructor is not noexcept std::vector cannot use it. since then it cannot ensure the exception guranteesdemnaded by the standard.
参考 :
http://book.2cto.com/201306/25351.html
4.override
描述:override保留字表示当前函数重写了基类的虚函数。
目的:1.在函数比较多的情况下可以提示读者某个函数重写了基类虚函数(表示这个虚函数是从基类继承,不是派生类自己定义的);2.强制编译器检查某个函数是否重写基类虚函数,如果没有则报错。
用法:在类的成员函数参数列表后面添加该关键字既可。
例子:
class Base {
virtual void f();
};
class Derived : public Base {
void f() override; // 表示派生类重写基类虚函数f
void F() override;//错误:函数F没有重写基类任何虚函数
};
注意:override只是C++保留字,不是关键字,这意味着只有在正确的使用位置,oerride才启“关键字”的作用,其他地方可以作为标志符(如:int override;是合法的)。
相关:override还有一个姊妹保留字final。
参考:
http://www.cnblogs.com/kyxyes/p/3995937.html
5.final
用在类上表示不能被继承,用在 virtual func上表示不能被重写。
参考:
http://blog.csdn.net/nighsen/article/details/6363370
6.decltype
let compiler find the type of an expression. semantic same with pyhon type(),semantic typeof()
用法1 declare return type
用法2。用于meta programming
用法3.use to pass the type of lambda func
format:
lambda have no default constructor and no assignment operator
1. [] 不截取任何变量
2. [&} 截取外部作用域中所有变量,并作为引用在函数体中使用
3. [=] 截取外部作用域中所有变量,并拷贝一份在函数体中使用
4. [=, &foo] 截取外部作用域中所有变量,并拷贝一份在函数体中使用,但是对foo变量使用引用
5. [bar] 截取bar变量并且拷贝一份在函数体重使用,同时不截取其他变量
6. [x, &y] x按值传递,y按引用传递
7. [this] 截取当前类中的this指针。如果已经使用了&或者=就默认添加此选项。
C++ 14以后可以使用 template
注意lmabda在没有捕获外界变量的情况下可以直接转换为函数指针,一旦捕获了就只能转换function<…> obj;
参考:
http://blog.csdn.net/booirror/article/details/26973611
http://blog.csdn.net/u010102854/article/details/52857312
区别 function http://blog.163.com/lvan100@yeah/blog/static/6811721420127511289750/
补充 : 将析构函数定义为私有意味着只能在堆上new对象并且使用者需要自己负责destroy对象。这是由于c++语言为静态语言在编译时需要对所有静态函数检查可入性,在栈上创建的不具有可入性。
参考:http://blog.csdn.net/zyq522376829/article/details/48438037
variadic template parameters
print tuple
1. make 语法
参考:
http://www.kuqin.com/shuoit/20150225/344882.html
http://lpn520.iteye.com/blog/774919
2.swap
参考:
http://www.cnblogs.com/xloogson/p/3360847.html
3.exception
参考:
http://blog.csdn.net/zkreats/article/details/50550786
http://www.cnblogs.com/crazyacking/p/4951638.html
4.set实现
set 是一个rb_tree 的adaptor具体实现如GNU4.9下
使用:
参考:http://www.cplusplus.com/reference/set/set/set/
http://blog.csdn.net/jinzhilong580231/article/details/8666877
5.remove_if meta programming
http://blog.csdn.net/tianshuai1111/article/details/7674327
partial_sum 实现Fib
模板实现编译其期间Fib
累加vector使用lambda
补充python 实现fib http://blog.csdn.net/buaa_shang/article/details/8283309
remove_if 使用
6.虚继承,多继承
https://www.oschina.net/translate/cpp-virtual-inheritance
http://blog.csdn.net/wangxingbao4227/article/details/6772579
http://blog.csdn.net/u013630349/article/details/47057929
7.memcpy(),memset(),memcmp()
注意区分POD(plain old data)
http://www.cnblogs.com/jingliming/p/4737409.html
http://www.cnblogs.com/mayingkun/p/3234137.html
模版内模版
非类型实参参考:http://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html
http://www.cnblogs.com/gw811/archive/2012/10/25/2736224.html
重点参考http://www.cnblogs.com/assemble8086/archive/2011/10/02/2198308.html
lambda 函数
variadic template parameter
补充 1.make语法,2.swap, 3.exception,4.set 实现,5.remove_if meta programming. 6.虚继承,7.多继承,8.memcpy(),memset(),memcmp()9. 模版内模版
关键字 =delete,=default,using, noexcept, override, final, decltype,
1.=default 通常对于 默认构造函数,拷贝构造函数,拷贝赋值构造函数,析构函数,+ 对应的move 构造函数,如果自定义了改函数则编译器不会自动产生该构造函数。 但是为了减轻开发负担在需要默认构造函数时可以= default指定让编译器帮忙产生该类型构造函数,如果不想要该类型构造函数 可以=delete。 =default,=delete 可以在类体内部和外部inline widget& widget::operator=(const widget&) = default;
=delete 可以用在函数提上表示禁止重载某一类函数
bool isLucky(int number); // original function bool isLucky(char) = delete; // reject chars bool isLucky(bool) = delete; // reject bools bool isLucky(double) = delete; // reject doubles and float
可以用来指定禁止某类模版偏特化
class Widget { public: template<typename T> void processPointer(T* ptr) { … } }; template<> void Widget::processPointer<void>(void*) = delete; // still public, but deleted
参考:
之前的实现形式时将该方法或特化声明在private中但不实现。
想使某一类class不自动产生 拷贝构造,拷贝赋值,可以定义一个uncopyable class 将其 拷贝构造,拷贝赋值放在private中可以避免其子类实现默认或非默认拷贝构造,拷贝赋值构造函数。
http://www.cnblogs.com/xinxue/p/5503836.html
2. using
//c++98 typedef std::unique_ptr<std::unordered_map<std::string,std::string>> Uptrmap; //same with C++ 11 using Uptrmap = std::unique_ptr<std::unordered_map<std::string,std::string>>; typedef void (*Fn) (int, const std::string&); //same with using Fn = void (*)(int, const std::string&); //容易识别Fn为其别名 //以下为区别 typedef cannot be a template template <typename T> using Vec = std::vector<T,Myalloc<T>> Vec<int> col;//可以编译通过 template<typename T> typedef std::vector<T,Myalloc<T>> Vec;//编译失败,error: a typedef cannot be a template //只能 typedef std:::vector<int,Myalloc<int>> Vec; //或者 template <typename T> clss Vec { typedef std::vector<T,MyAalloc<T>> type; }; Vec<int>::type col;//用在模板类内部或者进行参数传递时必须加上typename 用以指定为类型。 //即typedef不能直接作为模板使用
using value_type = T;//用在类内部代替typedef T value_type;
使用 using 别名后不能特化也不能偏特化
1.typedefs don’t support templatization, but alias declarations do.
2.Alias templates avoid the “::type” suffix and, in templates, the “typename” prefix often required to refer to typedefs.
3.C++14 offers alias templates for all the C++11 type traits transformations.
参考:
https://zhuanlan.zhihu.com/p/21264013
3.noexcept
从语法上讲,noexcept修饰符有两种形式,一种就是简单地在函数声明后加上noexcept关键字。比如:
void excpt_func() noexcept;
另外一种则可以接受一个常量表达式作为参数,如下所示:
void excpt_func() noexcept (常量表达式);
常量表达式的结果会被转换成一个bool类型的值。该值为true,表示函数不会抛出异常,反之,则有可能抛出异常。这里,不带常量表达式的noexcept相当于声明了noexcept(true),即不会抛出异常。
noexcept形如其名地,表示其修饰的函数不会抛出异常。不过与throw()动态异常声明不同的是,在C++11中如果noexcept修饰的函数抛出了异常,编译器可以选择直接调用std::terminate()函数来终止程序的运行,这比基于异常机制的throw()在效率上会高一些。这是因为异常机制会带来一些额外开销,比如函数抛出异常,会导致函数栈被依次地展开(unwind),并依帧调用在本帧中已构造的自动变量的析构函数等。
#include <iostream> using namespace std; void Throw() { throw 1; } void NoBlockThrow() { Throw(); } void BlockThrow() noexcept { Throw(); } int main() { try { Throw(); } catch(...) { cout << "Found throw." << endl; // Found throw. } try { NoBlockThrow(); } catch(...) { cout << "Throw is not blocked." << endl; // Throw is not blocked. } try { BlockThrow(); // terminate called after throwing an instance of 'int' } catch(...) { cout << "Found throw 1." << endl; } } //
BlockThrow() 会直接 terminate不会被catch
而noexcept作为一个操作符时,通常可以用于模板。比如:
template <class T> void fun() noexcept(noexcept(T())) {}
这里,fun函数是否是一个noexcept的函数,将由T()表达式是否会抛出异常所决定。这里的第二个noexcept就是一个noexcept操作符。当其参数是一个有可能抛出异常的表达式的时候,其返回值为false,反之为true(实际noexcept参数返回false还包括一些情况,这里就不展开讲了)。这样一来,我们就可以使模板函数根据条件实现noexcept修饰的版本或无noexcept修饰的版本。从泛型编程的角度看来,这样的设计保证了关于“函数是否抛出异常”这样的问题可以通过表达式进行推导。因此这也可以视作C++11为了更好地支持泛型编程而引入的特性。
比如在C++98中,存在着使用throw()来声明不抛出异常的函数。
template<class T> class A { public: static constexpr T min() throw() { return T(); } static constexpr T max() throw() { return T(); } static constexpr T lowest() throw() { return T(); } ... 而在C++11中,则使用noexcept来替换throw()。 template<class T> class A { public: static constexpr T min() noexcept { return T(); } static constexpr T max() noexcept { return T(); } static constexpr T lowest() noexcept { return T(); } ... 又比如,在C++98中,new可能会包含一些抛出的std::bad_alloc异常。 void* operator new(std::size_t) throw(std::bad_alloc); void* operator new[](std::size_t) throw(std::bad_alloc); 而在C++11中,则使用noexcept(false)来进行替代。 void* operator new(std::size_t) noexcept(false); void* operator new[](std::size_t) noexcept(false); 当然,noexcept更大的作用是保证应用程序的安全。比如一个类析构函数不应该抛出异常,那么对于常被析构函数调用的delete函数来说,C++11默认将delete函数设置成noexcept,就可以提高应用程序的安全性。 void operator delete(void*) noexcept; void operator delete[](void*) noexcept;
特别的 you need inform C++(specially std::vector,deque)that your move constructor and destructor does not throw. Then the move constructor will be called when vector grows. if the constructor is not noexcept std::vector cannot use it. since then it cannot ensure the exception guranteesdemnaded by the standard.
参考 :
http://book.2cto.com/201306/25351.html
4.override
描述:override保留字表示当前函数重写了基类的虚函数。
目的:1.在函数比较多的情况下可以提示读者某个函数重写了基类虚函数(表示这个虚函数是从基类继承,不是派生类自己定义的);2.强制编译器检查某个函数是否重写基类虚函数,如果没有则报错。
用法:在类的成员函数参数列表后面添加该关键字既可。
例子:
class Base {
virtual void f();
};
class Derived : public Base {
void f() override; // 表示派生类重写基类虚函数f
void F() override;//错误:函数F没有重写基类任何虚函数
};
注意:override只是C++保留字,不是关键字,这意味着只有在正确的使用位置,oerride才启“关键字”的作用,其他地方可以作为标志符(如:int override;是合法的)。
相关:override还有一个姊妹保留字final。
参考:
http://www.cnblogs.com/kyxyes/p/3995937.html
5.final
用在类上表示不能被继承,用在 virtual func上表示不能被重写。
参考:
http://blog.csdn.net/nighsen/article/details/6363370
6.decltype
let compiler find the type of an expression. semantic same with pyhon type(),semantic typeof()
用法1 declare return type
template <typename T1, typename T2> auto add(T1 a, T2 b)->decltype(a+b) {}
用法2。用于meta programming
typedef typename decltype(obj)::iterator iType;
用法3.use to pass the type of lambda func
auto cmp = [](const Person& p1, const Person& p2){ return p1.name() < p2.name(); } //此时想获得lambda type 用于设定set的cmp func std::set<Person, decltype(cmp)> coll(type);
Lambda 函数
define inline function can be used as a parameter or local obj.format:
[]()mutalbe throwspec ->retType{}
lambda have no default constructor and no assignment operator
1. [] 不截取任何变量
2. [&} 截取外部作用域中所有变量,并作为引用在函数体中使用
3. [=] 截取外部作用域中所有变量,并拷贝一份在函数体中使用
4. [=, &foo] 截取外部作用域中所有变量,并拷贝一份在函数体中使用,但是对foo变量使用引用
5. [bar] 截取bar变量并且拷贝一份在函数体重使用,同时不截取其他变量
6. [x, &y] x按值传递,y按引用传递
7. [this] 截取当前类中的this指针。如果已经使用了&或者=就默认添加此选项。
C++ 14以后可以使用 template
template <typename T> a = [=](const T& n) {cout << T << endl;} a<int>(1)
注意lmabda在没有捕获外界变量的情况下可以直接转换为函数指针,一旦捕获了就只能转换function<…> obj;
参考:
http://blog.csdn.net/booirror/article/details/26973611
http://blog.csdn.net/u010102854/article/details/52857312
区别 function http://blog.163.com/lvan100@yeah/blog/static/6811721420127511289750/
补充 : 将析构函数定义为私有意味着只能在堆上new对象并且使用者需要自己负责destroy对象。这是由于c++语言为静态语言在编译时需要对所有静态函数检查可入性,在栈上创建的不具有可入性。
参考:http://blog.csdn.net/zyq522376829/article/details/48438037
variadic template parameter
补充 求最大值两种方式1.initializer-listtemplate<typename _Tp> inline _Tp max(initializer_list<_Tp> __l) { return *max_element(__l.begin(),__l.end()); } template<typename _ForwardIterator> inline _ForwardIterator max(_ForwardIterator __first,_ForwardIterator __last) { return __max_element(__first,__last,__iter_less_iter()); } template<typename _ForwardIterator, typename _Compare> _ForwardIterator _max_element(_ForwardIterator __First, _ForwardIterator __Last,_Compare __comp){ if(__first == __last) return __first; ForwardIterator __result = __first; while(++__first != __last) if (__comp(__result,__first)) __result = __first; return __result; } inline _Iter_less_iter(){ return _Iter_less_iter(); }
variadic template parameters
int maximum(int n){ return n; } template<typename... Args> int maximum(int n, Args... args){ return std::max(n,maximum(args...)); }
print tuple
template <typename... Args> ostream& operator << (ostream& os, const tuple<Args...>& t){ os << "["; PRINT_TUPLE<0,sizeof...(Args),Args...>::print(os,t); return 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...>(os,t); } }; template <int MAX, typename...Args> struct PRINT_TUPLE<MAX,MAX,Args...>{ static void print (std::ostream& os,const tuple<Args...>& t){} };//end statment
- 补充 1.make语法,2.swap, 3.exception,4.set 实现,5.remove_if meta programming. 6.虚继承,7.多继承,8.memcpy(),memset(),memcmp()9. 模版内模版
##1. make 语法
参考:
http://www.kuqin.com/shuoit/20150225/344882.html
http://lpn520.iteye.com/blog/774919
2.swap
参考:
http://www.cnblogs.com/xloogson/p/3360847.html
3.exception
参考:
http://blog.csdn.net/zkreats/article/details/50550786
http://www.cnblogs.com/crazyacking/p/4951638.html
4.set实现
set 是一个rb_tree 的adaptor具体实现如GNU4.9下
template <typename _Key, typename _Compare = s s td::less<_Key>, typename _Allloc = std::allocator<_Key>> class set { typedef typename _Alloc::value_type _Alloc_value_type; public: typedef _Key key_type; typedef _Key value_type; typedef _Compare key_compare; typedef _Compare value_compare; typedef _Alloc allocator_type; private: typedef typename __gnu_cxx::__alooc_traits<_Alloc>::template rebind<_Key>::other _Key_alloc_type; typedef _Rb_tree<key_type, value_type, Identity<value_type>, key_compare, _Key_alloc_type> _Rep_type; _Rep_type _M_t;//adaptor define rb_tree typedef __gnu_cxx::__alloc_traits<_Key_alloc_type> _Alloc_traits; public: //Iterator relaited typedef typedef typename _Alloc_traits::pointer pointer; typedef typename _Alloc_traits::const_pointer const_pointer; typedef typename _Alloc_traits::reference reference; typedef typename _Alloc_traits::const_reference const_reference; typedef typename _Rep_type::const_iterator iterator; typedef typename _Rep_type::const_iterator const_iterator; typedef typename _Rep_type::const_reverse_iterator reverse_iterator; typedef typename _Rep_type::const_reverse_ierator const_reverse_iterator; typedef typename _Rep_type::size_type size_type; typedef typename _Rep_type::difference_type difference_type; set():_M_t(){} explicit set(const _Compare& __comp, const allocator_type& __a = allocator_type()) :_M_t(__comp,__key_alloc_type(__a)){} .... //C++11 set(set&& __x) noexcept(is_nothrow_copy_constructible<_Compare>::value) :_M_t(std::move(__x._M_t)){} set(initializer_list<value_type> __l, const allocator_type& __a = allocator_type()) :_M_t(__comp,_Key_alloc_type(__a)) //所有操作均是调用rb_tree内来实现 };
使用:
#include <iostream> #include <set> bool fncomp (int lhs, int rhs) {return lhs<rhs;} struct classcomp { bool operator() (const int& lhs, const int& rhs) const {return lhs<rhs;} }; int main () { std::set<int> first; // empty set of ints int myints[]= {10,20,30,40,50}; std::set<int> second (myints,myints+5); // range std::set<int> third (second); // a copy of second std::set<int> fourth (second.begin(), second.end()); // iterator ctor. std::set<int,classcomp> fifth; // class as Compare bool(*fn_pt)(int,int) = fncomp; std::set<int,bool(*)(int,int)> sixth (fn_pt); // function pointer as Compare return 0; }
参考:http://www.cplusplus.com/reference/set/set/set/
http://blog.csdn.net/jinzhilong580231/article/details/8666877
5.remove_if meta programming
http://blog.csdn.net/tianshuai1111/article/details/7674327
partial_sum 实现Fib
array<int, 10> input;//不会默认初始化 array<int,10> result; for(int i = 0; i < input.size();i++){ input[i] = i;//replace(iv.begin(),iv.end(),6,3);初始化可以用replace result[i] = 0; } partial_sum(input.begin(),input.end(),result.begin(),plus2<int>());//accumulate() int my_sum(int a, int b){return a + b;}
模板实现编译其期间Fib
template<int N> class Fib { public: enum{Result = Fib<N-1>::Result + Fib<N-2>::Result}; }; template<> Fib<1> class Fib { enum{Result = 1}; }; template<> Fib<0> class Fib{ enum{Result = 0}; }
累加vector使用lambda
std::for_each(vector.begin(), vector.end(), [&] (int n) { sum_of_elems += n; });
补充python 实现fib http://blog.csdn.net/buaa_shang/article/details/8283309
remove_if 使用
// remove_if example #include <iostream> // std::cout #include <algorithm> // std::remove_if bool IsOdd (int i) { return ((i%2)==1); } int main () { int myints[] = {1,2,3,4,5,6,7,8,9}; // 1 2 3 4 5 6 7 8 9 // bounds of range: int* pbegin = myints; // ^ int* pend = myints+sizeof(myints)/sizeof(int); // ^ ^ pend = std::remove_if (pbegin, pend, IsOdd); // 2 4 6 8 ? ? ? ? ? // ^ ^ std::cout << "the range contains:"; for (int* p=pbegin; p!=pend; ++p) std::cout << ' ' << *p; std::cout << '\n'; return 0; }
6.虚继承,多继承
https://www.oschina.net/translate/cpp-virtual-inheritance
http://blog.csdn.net/wangxingbao4227/article/details/6772579
http://blog.csdn.net/u013630349/article/details/47057929
7.memcpy(),memset(),memcmp()
注意区分POD(plain old data)
http://www.cnblogs.com/jingliming/p/4737409.html
http://www.cnblogs.com/mayingkun/p/3234137.html
模版内模版
非类型实参参考:http://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html
http://www.cnblogs.com/gw811/archive/2012/10/25/2736224.html
重点参考http://www.cnblogs.com/assemble8086/archive/2011/10/02/2198308.html
相关文章推荐
- (c++)sum=2+5+8+11+14+…,输入正整数n,求sum的前n项和。
- C++17/14/11 个人备忘
- 14-9-11 C/C++课程设计--图书馆管理系---<time.h>中时间数据类型的学习记录
- C++ 11/14 1
- C++ 11/14 3
- [GeekBand] 探讨C++新标准之新语法——C++ 11~14
- 现代C++(11/14/17)对并发的支持
- Thinking in C++ (1-11) 小结
- 11-14 Building a Quiz Engine
- |1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20所有这些字符串,把它的数字一个个剥离??
- C++ FAQ 11
- 孙鑫C++视频笔记(11)图形的保存和重绘
- C++ FAQ Lite[11]--析构函数(新)
- SIP协议解析与实现(c和c++ 使用osip) 11
- ANSI/ISO C++ Professional Programmer's Handbook 11
- C++复习 14 重载操作符与转换
- 11-30>pe_xscan 改进了O15、O14 和 O18 项的显示,log着色显示
- More Effective C++之11
- (11)'c++:COMPLETE REFERENCE' 第一部分 第二章(表达式) 第三节
- 07/11/14 资料整理