boost::process移植笔记
文章目錄
- process移植筆記
- 元函數(shù)
- 常規(guī)函數(shù)的基本要素
- 元函數(shù)使用場(chǎng)景舉例
- 元函數(shù)定義
 
- child類(lèi)
- child的構(gòu)造過(guò)程
- make_builders_from_view
- append_set
- get_initializers仿函數(shù)
 
- executor類(lèi)
- boost::fusion::transform_view引起的坑
 
 
- 樣例代碼
- 編譯
 
- 個(gè)人的一點(diǎn)疑問(wèn),如有錯(cuò)誤,歡迎大家指正
- boost::fusion的算法
- 管道的奇怪設(shè)計(jì)
- char_converter_t實(shí)現(xiàn)方式探討
- 深入char_converter
- 對(duì)char_converter通用實(shí)現(xiàn)版本的思考
- 為何沒(méi)有basic_native_environment的特化版本
 
 
- initializer_tag
 
 
- 相關(guān)鏈接
最近想做一個(gè)進(jìn)程管理器,因?yàn)檫@段時(shí)間在學(xué)boost,所以就選擇了boost::process,但一用才發(fā)現(xiàn),VC2010下編譯報(bào)錯(cuò)了。
原因是process中用到了不少C++11的語(yǔ)法,2010支持不完整。
所以,就有了這次的移植筆記。
不用告訴我VC2019可以完美支持,本人就是覺(jué)得VC2010夠清新簡(jiǎn)潔,不會(huì)啟動(dòng)那么多亂七八糟的進(jìn)程,浪費(fèi)資源,哈哈哈。
其實(shí)重復(fù)造輪子才能真正學(xué)到別人代碼的設(shè)計(jì)理念嘛,估計(jì)這個(gè)才算是瞎折騰的真正動(dòng)力。
移植后的代碼丟到github上了,地址在最后可以找到。
process移植筆記
元函數(shù)
元函數(shù)是在boost::mpl的文檔中看到的,感覺(jué)挺有意思,而且也被process大量使用,因此,有必要先做個(gè)鋪墊,這樣后面的內(nèi)容才好展開(kāi)。
在理解元函數(shù)之前,先看看C++中的一個(gè)常規(guī)函數(shù)長(zhǎng)啥樣,兩者結(jié)合,可能會(huì)更容易理解元函數(shù)的概念。
常規(guī)函數(shù)的基本要素
int MyFunc(int fld1) {//根據(jù)實(shí)際需要,干點(diǎn)有意義的事情return 111; }上面定義了一個(gè)函數(shù),名字為MyFunc,其包含3個(gè)重要部分:
- 入?yún)?/li>
- 函數(shù)體
- 返回結(jié)果
MyFunc的作用是:將輸入的入?yún)ld1,經(jīng)過(guò)一定的處理后,得到我們想要的結(jié)果111。
元函數(shù)使用場(chǎng)景舉例
為了對(duì)元函數(shù)有個(gè)初步印象,我們先來(lái)看一個(gè)實(shí)際的使用場(chǎng)景。
試想有個(gè)通訊模塊,負(fù)責(zé)將本機(jī)的數(shù)據(jù)發(fā)給遠(yuǎn)程主機(jī),這時(shí),我們要考慮以下這些問(wèn)題:
- 對(duì)于整數(shù)類(lèi)型,不同機(jī)器的字節(jié)序不一樣,有的是小端,有的是大端,傳輸時(shí),統(tǒng)一用大端
- 字符串,我們希望增加一個(gè)長(zhǎng)度指示符,用于接收方計(jì)算字符串的實(shí)際長(zhǎng)度
- 浮點(diǎn)數(shù),不同機(jī)器的表示格式不盡相同,我們將其轉(zhuǎn)換為整數(shù)后,再發(fā)送
按面向?qū)ο蟮脑O(shè)計(jì)思想,我們自然會(huì)想到,將不同的類(lèi)型,封裝成不同的類(lèi)。例如,CInt負(fù)責(zé)整數(shù)的大小端轉(zhuǎn)換,CStr負(fù)責(zé)字符串的處理,CFloat負(fù)責(zé)將浮點(diǎn)數(shù)轉(zhuǎn)換為64位的整數(shù)值。
接下來(lái),我們還需要定義一個(gè)Send函數(shù),負(fù)責(zé)數(shù)據(jù)的發(fā)送:
template<typename T> int Send(const T &t) {MyFunc<T> s(t); //注意,這里的代碼是不合法的,C++不支持這種語(yǔ)法,編譯會(huì)報(bào)錯(cuò)//將s轉(zhuǎn)換后的內(nèi)容,發(fā)送出去 }上面代碼想實(shí)現(xiàn)的目標(biāo)是:
這里的關(guān)鍵點(diǎn)在于對(duì)s的類(lèi)型聲明,如果有一個(gè)類(lèi)似MyFunc的“函數(shù)”,可以將輸入類(lèi)型T,轉(zhuǎn)換為我們想要的CInt、CStr等類(lèi)型的話,上面的代碼就能通過(guò)編譯了。
元函數(shù)定義
C++中并沒(méi)有元函數(shù)的聲明語(yǔ)法,在mpl中,是借用模板來(lái)實(shí)現(xiàn)的。
template<typename fld1> //元函數(shù)入?yún)?struct MyFunc {typedef ...... var1; //可使用typedef定義一些變量//std和mpl中,提供了一些標(biāo)準(zhǔn)模板,可實(shí)現(xiàn)類(lèi)似條件判斷、循環(huán)等操作typedef ...... type; //這個(gè)type就是元函數(shù)的返回結(jié)果,算是mpl中約定俗成的做法 };在MyFunc這個(gè)模板類(lèi)的“{}”內(nèi)部,相當(dāng)于是元函數(shù)的函數(shù)體,模板參數(shù)就是元函數(shù)的入?yún)?#xff0c;type為出參。
而我們前面寫(xiě)的Send函數(shù),就變成下面這個(gè)樣子:
template<typename T> int Send(const T &t) {MyFunc<T>::type s(t); //區(qū)別就在這里//將s轉(zhuǎn)換后的內(nèi)容,發(fā)送出去 }在真實(shí)世界中,元函數(shù)的實(shí)現(xiàn)往往不止一個(gè)模板定義,而是使用了模板部分特化技術(shù),分多個(gè)模板實(shí)現(xiàn)。代碼往往會(huì)分散在多個(gè)文件中,元函數(shù)更多只算是一種概念上的抽象。
 如下樣例所示:
child類(lèi)
child算是本次移植最核心的一個(gè)類(lèi),也是最有意思的一個(gè)類(lèi)。
 在C++中定義一個(gè)函數(shù),形參個(gè)數(shù)是固定的,而且入?yún)㈨樞蛞脖仨毢投x完全一致。
 但child卻非常“另類(lèi)”,并沒(méi)遵循這個(gè)基本原則,構(gòu)造時(shí),參數(shù)可以隨便輸。
 這種用法,我只在腳本語(yǔ)言中看到過(guò)。
為了實(shí)現(xiàn)以上用法,process通過(guò)下面這個(gè)特殊的構(gòu)造函數(shù),達(dá)到此目的:
// <boost/process/detail/child_decl.hpp> class child { public:template<typename ...Args>explicit child(Args&&...args); }// <boost/process/child.hpp> template<typename ...Args> child::child(Args&&...args): child(::boost::process::detail::execute_impl(std::forward<Args>(args)...)) {}核心邏輯在execute_impl這個(gè)函數(shù)中,其位于“<boost/process/detail/execute_impl.hpp>”,此函數(shù)只是做了下字符串的轉(zhuǎn)換,只要入?yún)⒅邪粋€(gè)unicode字符串,就將所有ansi字符串轉(zhuǎn)為unicode字符串。然后,將轉(zhuǎn)換后的參數(shù)轉(zhuǎn)發(fā)給basic_execute_impl處理,而child構(gòu)造的核心邏輯,就在此函數(shù)中。
child的構(gòu)造過(guò)程
在Windows中,創(chuàng)建進(jìn)程的API是CreateProcess。
 這個(gè)函數(shù)可以說(shuō)是相當(dāng)復(fù)雜,光入?yún)⒕陀?0個(gè),其中l(wèi)pStartupInfo這個(gè)結(jié)構(gòu)體,又有18個(gè)成員變量,這樣算下來(lái),就有27個(gè)要素需要關(guān)注。
process的做法是將這27個(gè)要素按功能相近程度進(jìn)行分類(lèi),每個(gè)類(lèi)別定義一個(gè)類(lèi)來(lái)處理(所有類(lèi)均從handler_base繼承)。
 例如,處理鏡像文件路徑、命令行入?yún)?#xff0c;使用類(lèi)exe_cmd_init,工作目錄設(shè)置用類(lèi)start_dir_init,異步管道用async_pipe_in、async_pipe_out等等。
basic_execute_impl先將入?yún)澐譃閮深?lèi):
之后的所有工作,實(shí)際上就是把第一類(lèi)入?yún)?#xff0c;轉(zhuǎn)換為handler_base的子類(lèi),然后,再和第二類(lèi)入?yún)⒅匦陆M合成新的數(shù)組,再交給executor類(lèi)創(chuàng)建進(jìn)程。
make_builders_from_view
make_builders_from_view是個(gè)元函數(shù),其作用是將第一類(lèi)入?yún)?#xff0c;轉(zhuǎn)換為builder類(lèi)的set集合。
 轉(zhuǎn)換過(guò)程分為兩個(gè)步驟,先使用initializer_tag元函數(shù)找tag標(biāo)識(shí)類(lèi),
 然后,再用這個(gè)標(biāo)識(shí)類(lèi),通過(guò)initializer_builder元函數(shù),找對(duì)應(yīng)的builder類(lèi)。
append_set
多個(gè)入?yún)⒂锌赡軐?duì)應(yīng)同一個(gè)builder類(lèi),make_builders_from_view在處理時(shí),需要提供相同類(lèi)合并的能力。
 由于在boost::fusion中沒(méi)找到類(lèi)似的功能,因此,就仿造as_vector,寫(xiě)了這個(gè)append_set元函數(shù)。
 這個(gè)元函數(shù)有兩個(gè)入?yún)?#xff1a;set類(lèi)型的類(lèi)型集合、新類(lèi)型。
 如果新類(lèi)型不在set中,append_set就會(huì)將新類(lèi)型添加到set中,得到一個(gè)新的set。
其中用到的關(guān)鍵技巧就在于對(duì)boost::fusion::result_of::size和迭代器的使用。
 使用size獲取原set中類(lèi)型的實(shí)際個(gè)數(shù),再通過(guò)迭代器將類(lèi)型展開(kāi),之后和新類(lèi)型一起,用as_set元函數(shù)構(gòu)造新set。
 類(lèi)型展開(kāi)的過(guò)程用到了模板特化,寫(xiě)起來(lái)有點(diǎn)繁瑣。
 如果編譯器支持可變模板參數(shù)的話,實(shí)現(xiàn)上可以簡(jiǎn)化很多。
通過(guò)append_set得到經(jīng)過(guò)整合的builder類(lèi)集合后,接下來(lái)就是將入?yún)⒅祩鹘o這些builder類(lèi)。
get_initializers仿函數(shù)
有了builder類(lèi)的集合,再借助boost::fusion中的for_each算法(可參考STL中的同名函數(shù)來(lái)理解),就可以通過(guò)builder類(lèi)創(chuàng)建我們最終的結(jié)果:handler_base子類(lèi)。
 算法中用到的仿函數(shù)就是get_initializers,其中除了對(duì)“operator ()”運(yùn)算符做重載外,還需要定義“operator ()”運(yùn)算符的返回值類(lèi)型result。
對(duì)于result元函數(shù),最初我是按下面這樣寫(xiě)的:
struct get_initializers {template<typename Element> //這里的Element,我最初以為是前面得到的builder類(lèi)型,但實(shí)際上理解錯(cuò)了struct result{typedef typename get_initializers_result<Element>::type type;};template<typename Element>typename result<Element>::typeoperator ()(Element &e) const{return e.get_initializer();} };上面的代碼無(wú)法通過(guò)編譯,這樣一來(lái),我們就沒(méi)法用單步調(diào)試的方式來(lái)定位問(wèn)題了。
 要排查boost::fusion的問(wèn)題,一定要學(xué)會(huì)閱讀編譯器的錯(cuò)誤輸出,如下樣例:
這是VC2010的實(shí)際輸出,越靠上面的錯(cuò)誤,在調(diào)用棧中,越靠近下面(按堆棧從高到低的方向壓入?yún)?shù)的角度來(lái)看的)。
 錯(cuò)誤分為3個(gè)部分:
實(shí)際上,上面的錯(cuò)誤信息,已經(jīng)把錯(cuò)誤原因告訴我們了,問(wèn)題就出在apply_transform_result上,我們先看看其定義:
// <boost/fusion/view/transform_view/detail/apply_transform_result.hpp> template <typename F> struct apply_transform_result {template <typename T0>struct apply<T0, void_>: boost::result_of<F(T0)> //關(guān)鍵點(diǎn)在這里{}; };關(guān)鍵點(diǎn)在result_of的模板參數(shù)上,這里實(shí)際上是個(gè)“函數(shù)類(lèi)型”,其入?yún)㈩?lèi)型為T(mén)0,返回值類(lèi)型為F。
 最終這個(gè)函數(shù)類(lèi)型,會(huì)傳遞給get_initializers::result,作為其Element入?yún)ⅰ?br /> 我們?cè)趓esult的實(shí)現(xiàn)中,實(shí)際想要的是函數(shù)類(lèi)型中的入?yún)㈩?lèi)型T0,而不是函數(shù)類(lèi)型本身。
 因此,對(duì)result的實(shí)現(xiàn)要做特化,將函數(shù)類(lèi)型展開(kāi):
雖然編譯器的錯(cuò)誤輸出,可為問(wèn)題排查提供不少信息,但在實(shí)際開(kāi)發(fā)中,還是有發(fā)現(xiàn)過(guò)信息輸出不完整(甚至是前后信息對(duì)不上)的情況,如果大家有更好的排查方法,歡迎指教。
 另外,boost提供了一個(gè)模板函數(shù)type_id,可在運(yùn)行時(shí)獲取類(lèi)型信息,但前提條件是程序能正常編譯,感覺(jué)在mpl框架下開(kāi)發(fā)時(shí),作用有限。
executor類(lèi)
進(jìn)程創(chuàng)建的最后一步,實(shí)際上就是對(duì)前面得到的handler_base子類(lèi)數(shù)組,一個(gè)個(gè)的調(diào)用其接口函數(shù),對(duì)CreateProcess函數(shù)的27個(gè)要素進(jìn)行賦值。過(guò)程如下:
boost::fusion::transform_view引起的坑
transform_view從邏輯上,可以當(dāng)成一個(gè)新的序列容器來(lái)看待,但容器中的值,只有在真正使用時(shí),才會(huì)創(chuàng)建,而且,在使用完后,會(huì)馬上釋放(相當(dāng)于使用了臨時(shí)變量)。
 executor中將cmd_line、work_dir等變量定義為指針類(lèi)型,這導(dǎo)致在遍歷transform_view中的元素時(shí),這些變量指向了一個(gè)臨時(shí)變量的地址,當(dāng)遍歷結(jié)束后,這些地址就失效了,導(dǎo)致后面進(jìn)程創(chuàng)建出現(xiàn)問(wèn)題。
 本次代碼移植,通過(guò)在transform_view之外,加了層as_vector調(diào)用,對(duì)轉(zhuǎn)換結(jié)果進(jìn)行緩存,來(lái)規(guī)避此問(wèn)題。
樣例代碼
#define BOOST_ASIO_HAS_MOVE 1 //boost::asio對(duì)右值引用的版本識(shí)別似乎有問(wèn)題,VC2010好像支持,這里手動(dòng)開(kāi)啟#include <boost/asio.hpp> #include <process/async_pipe.hpp> #include <process/child.hpp> #include <process/search_path.hpp> #include <process/io.hpp>int main(int argc, char* argv[]) {boost::asio::io_service ios;std::vector<char> buf(100);ets::process::async_pipe ap(ios);ets::process::child c(ets::process::search_path("cmd"), "/?", ets::process::std_out > ap);boost::asio::async_read(ap, boost::asio::buffer(buf),[&buf](const boost::system::error_code &ec, std::size_t size){std::cout << std::string(buf.begin(), buf.begin() + size);});ios.run();c.wait();int result = c.exit_code();return result; }樣例代碼選擇的是process官方教程中的異步IO樣例,為了適配VC2010,進(jìn)行了一點(diǎn)調(diào)整:
編譯
由于process中使用了filesystem這類(lèi)需要編譯的庫(kù),因此,需要先編譯boost,相關(guān)過(guò)程請(qǐng)參考官方文檔,本筆記不再贅述。
 boost的版本建議使用1.64,我是在這個(gè)版本上完成的遷移,其他版本不保證兼容。
 官方下載地址
編譯時(shí)的目錄結(jié)構(gòu):
boost4ets |__boost_1_64_0 | |__boost # boost源碼 | |__libs | |__tools |__fusion |__out | |__lib # boost編譯后生成的lib庫(kù)文件路徑 |__process # boost4ets定制版本的process源碼 |__test|__asyn_io.cpp # 本測(cè)試樣例源碼- boost_1_64_0是下載的boost_1_64_0.7z的解壓目錄
- out是按boost官方文檔,編譯出來(lái)的庫(kù)文件路徑
- fusion、process、test對(duì)應(yīng)本代碼庫(kù)
打開(kāi)VC2010的命令行編譯環(huán)境,將當(dāng)前路徑切換到boost4ets\test,輸入以下命令:
cl /I"..\boost_1_64_0" /I".." /D "WIN32" /D "NDEBUG" /MD /EHsc asyn_io.cpp /link /LIBPATH:"..\out\lib" "shell32.lib"如果編譯順利,會(huì)在當(dāng)前目錄下生成文件asyn_io.exe,執(zhí)行后有如下輸出:
D:\boost4ets\test>asyn_io.exe 啟動(dòng) Windows 命令解釋器的一個(gè)新實(shí)例CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V個(gè)人的一點(diǎn)疑問(wèn),如有錯(cuò)誤,歡迎大家指正
boost::fusion的算法
對(duì)basic_execute_impl中直接使用filter_if這類(lèi)算法(官方boost::process的做法),我表示沒(méi)有看懂。
 fusion中的很多算法,本質(zhì)上只是對(duì)view的一層包裝,但卻會(huì)增加一個(gè)副作用,就是給容器加上常量限定。
 如下是filter_if的代碼片段:
之后在executor類(lèi)中使用時(shí),由于很多handler_base子類(lèi)的on_setup聲明并未添加const,所以,應(yīng)該會(huì)導(dǎo)致編譯報(bào)錯(cuò)才對(duì)。
管道的奇怪設(shè)計(jì)
async_pipe在構(gòu)造時(shí),會(huì)創(chuàng)建兩個(gè)管道_source、_sink,前者用于讀,后者用于寫(xiě),所以,我最初想當(dāng)然的像下面這樣寫(xiě)代碼:
boost::asio::io_service ios; ets::process::async_pipe ap(ios);bp::child c("cmd.exe", ets::process::std_in < ap, ets::process::std_out > ap); //將標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出都重定向到ap我的本意是希望在進(jìn)程啟動(dòng)后,可以一邊讀取進(jìn)程的輸出,還想讓進(jìn)程在輸入流上等待我的操作,但實(shí)際上,進(jìn)程啟動(dòng)后,沒(méi)有任何輸出結(jié)果,進(jìn)程閃退。
通過(guò)排查代碼,發(fā)現(xiàn)在async_pipe_in(async_pipe對(duì)應(yīng)的handler_base子類(lèi),async_pipe_out有類(lèi)似邏輯)中有個(gè)奇怪的處理,其on_success事件會(huì)把輸出流的句柄關(guān)掉,個(gè)人理解,其原因有可能是async_pipe_in只處理輸入,因此,輸出流沒(méi)意義,刪除之。
但既然只用一個(gè)管道,為何在async_pipe中同時(shí)創(chuàng)建兩個(gè)句柄呢?
char_converter_t實(shí)現(xiàn)方式探討
這個(gè)類(lèi)是用來(lái)做字符類(lèi)型轉(zhuǎn)換的,在execute_impl中用到,最初在代碼移植時(shí),我將這個(gè)類(lèi)刪掉了,只要不混用字符集的話,也沒(méi)什么問(wèn)題。
 但在寫(xiě)這篇文章時(shí),因?yàn)闃永a中同時(shí)用了search_path和單字節(jié)字符串,編譯報(bào)錯(cuò),所以,才又將這個(gè)功能加回來(lái)了。
代碼使用“transform_view + 仿函數(shù)call_char_converter”的方式實(shí)現(xiàn),但在實(shí)現(xiàn)過(guò)程中遇到一個(gè)問(wèn)題,就是result該如何定義?
 由于char_converter(char_converter_t本質(zhì)上只是char_converter的別名定義)只有一個(gè)函數(shù)conv定義,最初的想法是能否用decltype通過(guò)函數(shù)返回值進(jìn)行推導(dǎo),代碼如下:
可惜編譯報(bào)錯(cuò)了,問(wèn)題出在...::conv(res_type())這行,報(bào)錯(cuò)原因有很多,例如,沒(méi)有默認(rèn)構(gòu)造函數(shù)、數(shù)組類(lèi)型無(wú)法構(gòu)造、引用類(lèi)型無(wú)法構(gòu)造等等。
感覺(jué)用decltype的路行不通,所以,我采用了一種笨辦法,針對(duì)每個(gè)char_converter,都定義一個(gè)類(lèi)型轉(zhuǎn)換的元函數(shù)(實(shí)際上是借鑒了transform_view定義仿函數(shù)的做法)。
新代碼如下:
template <typename Element>struct result<call_char_converter(Element &)>{typedef typename ets::process::detail::char_converter<Char, Element> res_char_converter;typedef typename boost::detail::tr1_result_of_impl<res_char_converter,Element,boost::detail::has_result_type<res_char_converter>::value>::type type; //這行的意思是,如果res_char_converter中有result_type定義,就將其作為返回類(lèi)型,否則,使用res_char_converter中的result元函數(shù)處理};下面是char_converter的實(shí)現(xiàn):
template<> struct char_converter<wchar_t, const char*> {typedef std::wstring result_type; //加了這行static std::wstring conv(const char* in){std::size_t size = 0;while (in[size] != '\0') size++;return ::ets::process::detail::convert(in, in + size);} };深入char_converter
對(duì)char_converter通用實(shí)現(xiàn)版本的思考
template<typename Char, typename T> struct char_converter {static T& conv(T & in){return in;}static T&& conv(T&& in){return std::move(in);}static const T& conv(const T & in){return in;} };這個(gè)實(shí)現(xiàn),個(gè)人認(rèn)為有兩個(gè)問(wèn)題:
因此,遷移后的代碼,我直接刪除了版本2和版本3的實(shí)現(xiàn),只保留了版本1,目前暫未發(fā)現(xiàn)問(wèn)題。
關(guān)于函數(shù)模板參數(shù)類(lèi)型的推導(dǎo),我參考了網(wǎng)上的一篇文章,地址為《C++之類(lèi)型推導(dǎo)》
為何沒(méi)有basic_native_environment的特化版本
針對(duì)環(huán)境變量的處理,提供了兩個(gè)類(lèi):basic_native_environment、basic_environment。
char_converter有針對(duì)basic_environment的特化版本,但沒(méi)有提供basic_native_environment的。
 最初個(gè)人對(duì)這兩個(gè)類(lèi)的關(guān)系理解錯(cuò)了,所以,對(duì)process只提供一個(gè)版本的特化不是太理解。
 看了實(shí)現(xiàn)代碼后才知道:
- basic_native_environment是用來(lái)操作當(dāng)前進(jìn)程的環(huán)境變量的,相當(dāng)于是對(duì)GetEnvironmentStrings、SetEnvironmentVariable這些系統(tǒng)API的包裝,一旦通過(guò)其修改某個(gè)環(huán)境變量的值,實(shí)際上會(huì)影響當(dāng)前進(jìn)程的執(zhí)行
- basic_environment可以理解為是鍵值對(duì)的數(shù)組,對(duì)其修改,不會(huì)影響當(dāng)前進(jìn)程,當(dāng)創(chuàng)建子進(jìn)程時(shí),應(yīng)該通過(guò)這個(gè)類(lèi)來(lái)為子進(jìn)程指定新的環(huán)境變量
在使用時(shí),可以先用basic_native_environment獲取當(dāng)前進(jìn)程環(huán)境變量的值后,導(dǎo)入到basic_environment中,再根據(jù)需要對(duì)部分值進(jìn)行修改,然后,用修改后的basic_environment創(chuàng)建新進(jìn)程。
initializer_tag
char sExec[] = "cmd"; ets::process::child c(sExec);上面這段代碼編譯會(huì)報(bào)錯(cuò),提示error C2027: 使用了未定義類(lèi)型“ets::process::detail::initializer_tag<T>”。
 錯(cuò)誤原因是sExec的類(lèi)型是char (&)[4],而initializer_tag只針對(duì)常量版本的字符數(shù)組提供了定義:
從這點(diǎn)來(lái)看,感覺(jué)1.64版本的process庫(kù),也有可以完善的地方。
相關(guān)鏈接
- 作者郵箱: xinghun87@163.com
- 作者博客:https://blog.csdn.net/xinghun61
- github地址:boost4ets
總結(jié)
以上是生活随笔為你收集整理的boost::process移植笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
 
                            
                        - 上一篇: iOS 全景播放器最简单的解决方案
- 下一篇: arcgis出图详细步骤
