之前了解過一些c++
新標準的內容,覺得很不錯,在此寫篇小記,簡易推薦一下~
容器內元素操作是個很普通的需求,工作中應是屢見不鮮,這裡假設有個list
容器,儲存的是一系列
intc++
表達一下,大概是這個樣子:
#ifndef __test_1_h__
#define __test_1_h__
#include #include void add_one(int& val)
void add(std::list& l)
}void print_one(const int& value)
void print(const std::list& l)
std::cout << std::endl;
}void test() ;
std::listl;
for (int i = 0; i < sizeof(ages) / sizeof(int); ++i)
print(l);
add(l);
print(l);
}#endif
簡單看看,似乎寫的還行:**格式統一,函式命名也相對明確,引數上使用了(常量)引用來傳遞,效率上應該不錯,訪問容器元素使用了迭代器,模式上很經典呀~
不過仔細再看,那幾個迭代器的宣告還是略顯冗長了一些,list
容器的初始化也不是那麼簡明,更大的乙個問題是,**沒啥通用性,容器型別換一下,**大抵得重寫,而且內容都是重複的~
好吧,既然問題找到了,那就來嘗試改善一下:迭代器的宣告可以用typedef
簡化,不過更好的自然是直接迴避迭代器宣告,這裡我們剛好可以借助
std::for_each
來達到目的,
list
的初始化可以改用迭代器版本的建構函式,可以節省不少**,至於通用性的問題,模版幾乎都是標準答案~
一陣改造之後,**大概成了這樣:
#ifndef __test_2_h__
#define __test_2_h__
#include #include #include #include templatevoid add_one(t& val)
templatevoid add(container& container)
templatevoid print_one(const t& value)
templatevoid print(const container& container)
void test() ;
std::listl(ages, ages + sizeof(ages) / sizeof(int));
print(l);
add(l);
print(l);
std::vectorv(ages, ages + sizeof(ages) / sizeof(int));
print(v);
add(v);
print(v);
}#endif
改造後的**感覺已經不錯了,沒有冗長的迭代器宣告,沒有累贅的初始化過程,通用性也不錯,容器換做vector
,**一樣工作~
那麼問題來了:上面的**還能更簡潔嗎?
答案是可以!
先上**:
#ifndef __test_3_h__
#define __test_3_h__
#include #include #include #include void test() ;
auto add = [&add_one](auto& container) ;
auto print_one = (const auto& val) ;
auto print = [&print_one](const auto& container) ;
std::listl = ;
print(l);
add(l);
print(l);
std::vectorv = ;
print(v);
add(v);
print(v);
int a = ;
print(a);
add(a);
print(a);
}#endif
不太了解c++
新標準的同學現在可能已經在心裡暗罵了:什麼鬼?!不急,咱們一行行來看:
auto add_one = (auto& val);
auto 本來便是
c++中的乙個關鍵字,用於自動變數的宣告(雖然我從來也沒用過),在
c++11
中,它的作用(之一)變成了自動型別推導,還記得最早的那個迭代器宣告嗎:
std::list
::const_iterator beg = l.begin();
使用auto
的話只要這麼寫就行了,很舒服:
auto beg = l.begin();
所以這裡我們就是定義了乙個自動型別推導的add_one
變數,至於後面那個詭異的初始化表示式:
(auto& val)
其實是c++11
新引入的
lambda
表示式,用以方便的就地定義匿名函式物件,以上面的**為例來簡單說明一下:
中用於定義捕獲子句,至於什麼是捕獲子句,我們暫時不管,反正這裡我們什麼都沒填~
(auto& val
)則是引數列表,這個對於我們就很親切熟悉了,至於為什麼引數寫成
auto&
,而不是
int&
之類的方式,其實是使用了
c++14
中新定義的通用
lambda
功能,個人認為可以理解為定義模版,即
auto& val
可以看作
t& val
,用於匹配不同型別~
至於{ ++val;
}就是函式體了,沒啥好說的,一目了然~
ok,現在為止,
add_one
的定義就清楚了,簡單來說,它其實就是乙個接受單個引數的函式物件~
add_one搞明白了,那麼
add自然也大概清楚了:
auto add = [&add_one](auto& container) ;
這裡我們用到了c++11
以來新增的初始化列表,簡單來說就是,新標準的標準庫容器都新增了乙個以
initializer_list
為引數的建構函式,上述表示式中的
會被構造為乙個
initializer_list
並傳入list
的建構函式,之後便是一般的初始化流程了
~可以看到,初始化列表的引入讓容器的初始化變得非常簡潔,並且對於非標準庫的容器,你也可以為它定義以
initializer_list
為參的建構函式,同樣可以使用上面的初始化方式~
至此,我們使用更少的**,更簡潔易讀的表達出了程式邏輯,並且程式的通用性更強,而且程式的效率並沒有任何損失,cool~
c++新標準還遠遠不止上面提到的內容,像
nullptr
,override
,final
等新加入的關鍵字也很貼心,更有像智慧型指標、
move
語義等強大的工具加盟,當然了,另有一些個人感覺頗為晦澀的東西引入(
memory order etc.
),但是管他呢,慢慢了解便是,總體上,個人強烈建議有興趣的童鞋了解學習
c++新標準,
這裡就是個很好的開始~
C 11 14特性備忘
template auto add t x,u y int array for auto x array include 建構函式列表初始化 class magic magic magic std vector int v 普通函式形參 void func std initializer list ...
C 11 14 自動型別推導 auto
從c 11起,auto關鍵字不再表示儲存型別,而是成為了隱式型別定義關鍵字,其作用是讓編譯器在編譯期 便自動推斷出變數的型別。例如 auto a 1 a 為 int 型變數 auto ptr new auto 1 auto 1 int 1 ptr 為 int 型指標變數 const auto q a...
C 11 14之可變參模板
可變參類模板 variadic template 允許模板中有0到任意個模板引數 t emplate typename.t void myfunc t.ar s myfunc 0 0 myfunc 11 23 2 2 myfunc 14 12.4 nj 3 4 4 ar s 稱為一包或者一堆引數,這...