C语言的VC开发环境界面介绍,【c语言在vc++6.0中编写界面程序】
到現在為止,C++ 仍然是計算機編程領域的經典語言之一,C++ 17 標準在2017上半年已經探討確定。本期我們匯集了編程專家——祁宇(《深入應用 C++ 11》作者,C++ 開源社區 purecpp.org 創始人)的多年心得小結,并具體介紹了 C++ 17 最新標準中值得開發者關注的新特點和基本用法。
文/祁宇
本文將借助分析 magic _ get 源碼來介紹 magic _ get 實現的關鍵科技,深入剖析實現 pod 類型反射的機理。
反射是一種根據元數據來獲得類外部信息的模式,通過元數據就可以獲得對象的字段和技巧等信息。C# 和 Java 的反射模式都是通過獲得對象的元數據來推動的。反射可以用于依賴注入、ORM 對象-實體映射、序列化和反序列化等與對象原本信息密切相關的領域。比如 Java 的 Spring 框架,其依賴注入的基礎是構建在反射的基礎之上的,可以按照元數據獲取類型的信息并動態建立對象。ORM 對象-實體之間的映射也是借助反射實現的。Java 和 C# 都是基于前面運行時的語言,中間運行時提供了反射模式,所以反射針對運行時語言來說很容易,但是針對沒有中間運行時的語言,要想實現反射是很困難的。
在2016年的 CppCon 技術大會上,Antony Polukhin 做了一個關于 C++ 反射的發言vc6.0怎么寫c語言,他強調了一個實現反射的新思路,即無需使用宏、標記和額外的軟件就能推動反射??雌饋硭坪跏且患灰苍S完成的任務,因為 C++ 是沒有反射模式的,無法直接獲得對象的元信息。但是 Antony Polukhin 發現對 pod 類型使用 Modern C++ 的模板元方法可以實現這種的編譯期反射。他開源了一個 pod 類型的編譯期反射庫 magic _ get(),這個庫也打算開啟 boost。我們來看看 magic _ get 的使用示例。
#include struct foo { int some_integer; char c;};foo f {777, '!'};auto& r1 = boost::pfr::flat_get<0>(f); //通過索引來訪問對象foo的第1個字段auto& r2 = boost::pfr::flat_get<1>(f); //通過索引來訪問對象foo的第2個字段
通過這個例子可以發現,magic _ get 確實實現了非侵入式訪問 foo 對象的數組,不需要寫任何宏、額外的代碼或者專門的軟件,直接在編譯期就可以訪問 pod 對象的數組,沒有運行期負擔,確實有點 magic。
本文將借助分析 magic _ get 源碼來介紹 magic _ get 實現的關鍵科技,深入剖析實現 pod 類型反射的機理。
實現 pod 類型反射的模式是這么的:先將 pod 類型轉化為對應的 tuple 類型,接下來將 pod 類型的值賦給 tuple,然后就可以通過索引去訪問 tuple 中的元素了。所以推動 pod 反射的關鍵就是如何將 pod 類型轉化為對應的 tuple 類型和 pod 值數組給 tuple。
pod 類型對應的 tuple 類型是什么樣的呢?以下面的 foo 為例,foo 對應的 tuple 應該是 tuple,即 tuple 中的元素種類和排序和 pod 類型中的數組完全一一對應。
根據結構體生成一個 tuple 的基本模式是,按次序將結構體中每個數組的類別萃取出來并儲存起來,后面再取下來生成對應的 tuple 類型。然而字段的類別是不同的,C++ 也沒有一個能直接保存不同類型的容器vc6.0怎么寫c語言,因此必須一個變通的方式,用一個間接的方式來儲存萃取出來的字段類別,即將類型轉化為一個 size _ t 類型的 id,將這個 id 保存到一個 array 中,后面根據這個 id 來獲得實際的 type 并生成對應的 tuple 類型。
這里應該解決的一個問題是怎樣推動類型和 id 的互相轉換。
先通過一個空的模板類用來存放實際的類別,再通過 C++ 14 的 constexpr 特性,在編譯期返回某個類別對應的編譯期 id,就可以實現 type 轉換為 id 了。具體代碼如下:
https://ipad-cms.csdn.net/cms/article/code/3445
上面的代碼在編譯期將類別 int 和 char 做了一個編碼,將類別轉換為一個具體的編譯期常量,后面就可以按照這種編譯期常量來獲得對應的詳細類型。
編譯期根據 id 獲取 type 的代碼如下:
constexpr auto id_to_type( std::integral_constant<:size_t> ) noexcept { int res{}; return res; }constexpr auto id_to_type( std::integral_constant<:size_t> ) noexcept { char res{}; return res; }
上面的代碼中 id _ to _ type 返回的是 id 對應的類別的示例,如果要獲得 id 對應的類別還必須借助 decltype 推導出來。magic _ get 通過一個宏將 pod 基本類別都做了一個編碼,以推動 type 和 id 在編譯期的互相轉換。
#define REGISTER_TYPE(Type, Index) \ constexpr std::size_t type_to_id(identity) noexcept { return Index; } \ constexpr auto id_to_type( std::integral_constant<:size_t index=""> ) noexcept { Type res{}; return res; } \// Register all base types here REGISTER_TYPE(unsigned short , 1) REGISTER_TYPE(unsigned int , 2) REGISTER_TYPE(unsigned long long , 3) REGISTER_TYPE(signed char , 4) REGISTER_TYPE(short , 5) REGISTER_TYPE(int , 6) REGISTER_TYPE(long long , 7) REGISTER_TYPE(unsigned char , 8) REGISTER_TYPE(char , 9) REGISTER_TYPE(wchar_t , 10) REGISTER_TYPE(long , 11) REGISTER_TYPE(unsigned long , 12) REGISTER_TYPE(void* , 13) REGISTER_TYPE(const void* , 14) REGISTER_TYPE(char16_t , 15) REGISTER_TYPE(char32_t , 16) REGISTER_TYPE(float , 17) REGISTER_TYPE(double , 18) REGISTER_TYPE(long double , 19)
將類別編碼以后,保存在那里或者怎么取下來是接著要緩解的難題。magic _ get 通過定義一個 array 來保存結構體字段類別 id。
template struct array { typedef T type; T data[N]; static constexpr std::size_t size() noexcept { return N; } };
array 中的定長數組 data 中保存數組類型對應的 id,數組下標就是字段在結構體中的位置索引。
前面介紹了怎樣實現字段類別的保存和獲得,那么這個字段類別是怎樣從 pod 結構體中萃取出來的呢?具體的做法分為三步:
下面是詳細實現代碼:
template constexpr auto fields_count_and_type_ids_with_zeros() noexcept { static_assert(std::is_trivial::value, "Not applyable"); array<:size_t sizeof> types{}; detect_fields_count_and_type_ids(types.data, std::make_index_sequence{}); return types;}template constexpr auto array_of_type_ids() noexcept { constexpr auto types = fields_count_and_type_ids_with_zeros(); constexpr std::size_t count = count_nonzeros(types); array<:size_t count=""> res{}; for (std::size_t i = 0; i < count; ++i) { res.data[i] = types.data[i]; } return res; }
定義 array 時必須定義一個固定的變量長度,長度為多少適合呢?應按結構體最多的字段數來確認。因為結構體的數組數最多為 sizeof(T),所以 array 的長度設置為 sizeof(T)。array 中的元素全部初始化為0。一般情況下,結構體字段數通常不會超過 array 的厚度,那么 array 中就經常出現多余的元素,所以還必須將 array 中多余的數組移除,只儲存有效的泛型類別 id。具體的做法是計算出 array 中非零的元素有多少,接著再把非零的元素賦給一個新的 array。下面是推導 array 非零元素個數,同樣是通過 constexpr 實現編譯期計算。
本文來自電腦雜談,轉載請注明本文網址:
http://www.pc-fly.com/a/jisuanjixue/article-129594-1.html
總結
以上是生活随笔為你收集整理的C语言的VC开发环境界面介绍,【c语言在vc++6.0中编写界面程序】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MFC BEGIN_MESSAGE_MA
- 下一篇: VC++中的char,wchar_t,T