什麼是 header only? 可以先看此文了解一下 http://zevoid.blogspot.com/2012/04/c11-extern-template.html
簡單的說,header only 是把一個 class 的程式碼就包含在這個 class 中,而這個 class 就放在引入檔(.h)中供大家使用。有別於引入檔只放 class 介面,程式碼則放在 .cpp 中。
header only 的好處是執行快,因一大部份的函數可以用 inline 的方式呼叫,另外也不用再加 .cpp 或是還要連結程式庫(lib 或 dll)。
但有一個不得不面對的問題,class 的程式碼因不放在特定的 .cpp 中,那麼使用它的模組(exe、lib、dll)都得編譯出各別的執行碼,一般來說除了程式會比較胖之外,也沒有其它不好的影響。但是遇到插件就出問題了。
插件是一個 dll 檔,特點是要用的時候才載入,不用的時候可以卸載,但若某一個 class 產生的物件,其執行碼在那個被卸載的 dll 中,就會出大問題了,以下範例程式就是在演示這種情況。
2018年10月26日 星期五
2018年10月25日 星期四
[轉貼分享]將巨集展開後連結
https://stackoverflow.com/questions/6669551/converting-string-macros-constants-to-wide-characters-unicode
#define WIDEN(quote) WIDEN2(quote)
#define WIDEN2(quote) L##quote
#define VERSIONSTR "Test V1.2.3"
#define VERSIONSTRW WIDEN(VERSIONSTR)
#define WIDEN(quote) WIDEN2(quote)
#define WIDEN2(quote) L##quote
#define VERSIONSTR "Test V1.2.3"
#define VERSIONSTRW WIDEN(VERSIONSTR)
**補充說明**
搞懂了,原來 C++ 的巨集參數採用量子疊加技術,看這例子
#define WIDEN(quote) string xx##quote = quote
#define VERSIONSTR "Test V1.2.3"
#define VERSIONSTRW WIDEN(VERSIONSTR)
WIDEN(quote) 的 quote 是兩種狀態的疊加 -- VERSIONSTR + "Test V1.2.3"
若 quote 是單獨使用會塌縮成 "Test V1.2.3"
若 quote 和 ## 或 # 一起使用會塌縮成 VERSIONSTR
現在可以解釋原題了
#define WIDEN(quote) WIDEN2(quote) // 會展開成 WIDEN2("Test V1.2.3"),已無疊加
#define WIDEN2(quote) L##quote // 會展開成 L"Test V1.2.3"
#define VERSIONSTR "Test V1.2.3"
#define VERSIONSTRW WIDEN(VERSIONSTR) // VERSIONSTR 和 "Test V1.2.3" 的疊加
#define WIDEN(quote) string xx##quote = quote
#define VERSIONSTR "Test V1.2.3"
#define VERSIONSTRW WIDEN(VERSIONSTR)
WIDEN(quote) 的 quote 是兩種狀態的疊加 -- VERSIONSTR + "Test V1.2.3"
若 quote 是單獨使用會塌縮成 "Test V1.2.3"
若 quote 和 ## 或 # 一起使用會塌縮成 VERSIONSTR
現在可以解釋原題了
#define WIDEN(quote) WIDEN2(quote) // 會展開成 WIDEN2("Test V1.2.3"),已無疊加
#define WIDEN2(quote) L##quote // 會展開成 L"Test V1.2.3"
#define VERSIONSTR "Test V1.2.3"
#define VERSIONSTRW WIDEN(VERSIONSTR) // VERSIONSTR 和 "Test V1.2.3" 的疊加
2018年8月5日 星期日
外積公式推導
會寫此文是因 http://elearning.stut.edu.tw/mechanical/Statics/newpage23.htm 這網頁已失效了,這網頁對外積公式有很清楚的推導,所以覺得很可惜。但完整的內容也不可能記住,所以只能依賴模糊的記憶和網上收集資料盡力幫他還原。
首先我先表達我個人(既然說是個人表示是猜測,因此歡迎指正)對外積的看法,我認為這東西應該是發明出來的,原因是這東西是用來描述力矩,力矩具有大小和正負,但看不出它具有方向,也就是說力矩好像是一個純量(大陸那邊好像叫標量),但純量是可以任意相加減,可是力矩又不能這樣做,就好像力矩具有不同的質。
但透過外積,這個質可以描述出來了,只要同質就可以相加減了,因此外積是一個很聰明的發明,但這個力矩的向量值只能當作質,不能當作施力的方向。但可以由三維空間中兩條向量算出第三條垂直向量這一點,在 3D 繪圖是很重要的功能。
首先我先表達我個人(既然說是個人表示是猜測,因此歡迎指正)對外積的看法,我認為這東西應該是發明出來的,原因是這東西是用來描述力矩,力矩具有大小和正負,但看不出它具有方向,也就是說力矩好像是一個純量(大陸那邊好像叫標量),但純量是可以任意相加減,可是力矩又不能這樣做,就好像力矩具有不同的質。
但透過外積,這個質可以描述出來了,只要同質就可以相加減了,因此外積是一個很聰明的發明,但這個力矩的向量值只能當作質,不能當作施力的方向。但可以由三維空間中兩條向量算出第三條垂直向量這一點,在 3D 繪圖是很重要的功能。
2018年7月7日 星期六
快速排序法改良版
因遞廻會有爆掉堆疊的危險,所以若有可能盡可能用廻圈,但是不是可以用廻圈取決於關鍵變數,在一個廻圈後是不是須要保留其值,若不須要則可以重設其值,進行下一個廻圈的運行
以下用快速排序法做進一步的說明,先說它的改良法是青衫教的,我一直銘記在心
因快速排序法運行一個回合後會由定位點分割成左右兩部份,若要重設關鍵變數再處理左邊部份,右邊就失去關鍵變數沒法處理,反過來做亦相同,因此就讓較短的那邊用遞廻,長的那邊用廻圈
以下用快速排序法做進一步的說明,先說它的改良法是青衫教的,我一直銘記在心
因快速排序法運行一個回合後會由定位點分割成左右兩部份,若要重設關鍵變數再處理左邊部份,右邊就失去關鍵變數沒法處理,反過來做亦相同,因此就讓較短的那邊用遞廻,長的那邊用廻圈
2018年5月8日 星期二
猜數字 - ML 多國語言應用範例
這是一個實驗程式,有兩個實驗目標。
- 測試 ML 在 主程式 和 插件 是否能各別建立自己的多國語言能力,但兩者間又能互通,因插件可能和主程式在不同時期或不同人所開發,因此能否各別獨立建立自己的多國語言能力,勢必成為必須的目標。但還得讓插件可以隨主程式一起變動,這是可選擇性的,但卻是最常用的選項。這部份的實驗很成功,同時使用 "wxWidgets 的延伸控制件 for ML" 可以即時更動 GUI 的文字語言,結果很令人滿意。
- 測試 主程式 和 插件 間的非同步互動,這部份花了最多時間,也很雜亂,應該還有 bug 存在,因有時還是會出槌。因為是非同步處理所以抓 bug 又很麻煩,所以點到就好了,主要還是在 ML 的實驗。事後想想若一開始用圖靈機制規劃好應該會比較容易。
主程式所用的譯文檔置於 Lang 子目錄下,插件所用的譯文檔在 plugin\GuestCore_1_0\Lang,插件還提供機器人用的 密語,純好玩別當真,可用 MLedit 增修更多語言的譯文檔。
2018年5月7日 星期一
MLedit 多國語言編輯器
這是為 ML 插件製作譯文檔的輔助程式,本身所用的譯文檔置於 Lang 子目錄下,觀迎大家幫忙擴增更多語言的譯文。
下載點:
完整檔案包,可直接執行 MLedit.exe
精簡檔案包,適用於已安裝 CxxlMan2 開發環境懶人包,執行 "MLedit.exe - 捷徑 "
原始檔案包,適用於已安裝 CxxlMan2 開發環境懶人包,解壓到 C:\MySrc,支援 CMake 建立編譯專案
以下為新版:
下載點:
完整檔案包,可直接執行 MLedit.exe
MLedit_0.1.0_complete.7z
精簡檔案包,適用於已安裝 CxxlMan2 開發環境懶人包,執行 "MLedit.exe - 捷徑 "
MLedit_0.1.0_simplify.7z
原始檔案包,適用於已安裝 CxxlMan2 開發環境懶人包,解壓到 C:\MySrc,支援 CMake 建立編譯專案
MLedit_0.1.0_Src.7z
以下為新版:
CxxlMan2 開發環境懶人包
這是以 CodeBlocks 為開發環境架構出來的懶人包,包含 CxxlMan2 程式庫和插件、MinGw 5.1 以及 wxWidgets 3.1.1,內含設置說明
CxxlMan2 開發環境懶人包 20180606.7z
2018年5月6日 星期日
wxWidgets 的延伸控制件 for ML(多國語言插件)
延伸 wxWidgets 的控制件,達成和 ML 互動
延伸出的控制件的命名為原控制件名稱後多加 Ext,如:wxMenuExt
配合 CodeBlocks 的 wxSmith 的用法以順利取代原控件
目前提供的控制件如以下所列,可依樣畫葫蘆自己增加
延伸出的控制件的命名為原控制件名稱後多加 Ext,如:wxMenuExt
配合 CodeBlocks 的 wxSmith 的用法以順利取代原控件
目前提供的控制件如以下所列,可依樣畫葫蘆自己增加
2018年4月8日 星期日
instal 是 windows 執行檔名的特殊關鍵字
只要執行檔名含有 instal,無論位於哪個位置都會被視為安裝程式,不會用一般程式的方式啟動,害我抓 bug 抓了老半天
jhfcaginstalhfhgfg.exe 這個不是一般程式
jhfcaginstalhfhgfg.exe 這個不是一般程式
2018年4月5日 星期四
nPr 排列法
這方法會比旋轉要來得快
#include <functional> // std::function #include <memory> // std::shared_ptr #include <vector> #include <iostream> using namespace std; // n 取 r 做排列 // 採用逆時旋轉排列法 // 必須 n >= r class Permutation_nPr { // 回報結果 function<void(const shared_ptr<vector<unsigned char> > &, size_t)> m_Report; // 放置要排列的數字 shared_ptr <vector<unsigned char> > m_Digital_Array; // 要做排列的數目值 size_t m_r; void v(size_t n, size_t r) { if (r == 0) m_Report(m_Digital_Array, m_r); else v(n - 1, r - 1); for (size_t j = n; j > 0; --j) { { unsigned char tmp = m_Digital_Array->at(n); m_Digital_Array->at(n) = m_Digital_Array->at(j-1); m_Digital_Array->at(j - 1) = tmp; } if (r == 0) m_Report(m_Digital_Array, m_r); else v(n - 1, r - 1); { unsigned char tmp = m_Digital_Array->at(n); m_Digital_Array->at(n) = m_Digital_Array->at(j-1); m_Digital_Array->at(j - 1) = tmp; } } } public: Permutation_nPr( const function<void(const shared_ptr<vector<unsigned char> > &, size_t)> &Receive ):m_Report(Receive) {} void nPr(size_t n, size_t r) { m_r = r; m_Digital_Array = shared_ptr<vector<unsigned char> >(new vector<unsigned char>(n)); size_t i = n; while (i--) { m_Digital_Array->at(i) = i; } v(n - 1, r - 1); } }; class MsgShow { int N{1}; public: void ResetN(){N = 1;} void operator()( const shared_ptr<vector<unsigned char> > &Digital_Array, size_t r) { cout << N << ":\t"; for (size_t i = Digital_Array->size() - 1; r > 0; --i, --r) cout << (int)Digital_Array->at(i) << ' '; cout << endl; ++N; } }; int main() { MsgShow Report; Permutation_nPr P(Report); cout << '\n' << "4P3 排列:" << endl; Report.ResetN(); P.nPr(4,3); return 0; }
2018年3月15日 星期四
n 取 r 逆時鐘旋轉排列法
#include <functional> // std::function
#include <memory> // std::shared_ptr
#include <vector>
#include <iostream>
using namespace std;
// n 取 r 做排列
// 採用逆時旋轉排列法
// 必須 n >= r
class Permutation_nPr
{
// 回報結果
function<void(const shared_ptr<vector<unsigned char> > &, size_t)> m_Report;
// 放置要排列的數字
shared_ptr <vector<unsigned char> > m_Digital_Array;
// 要做排列的數目值
size_t m_r;
void v(size_t n, size_t r)
{
size_t i = n + 1;
while (i--)
{
if (r == 0)
m_Report(m_Digital_Array, m_r);
else
v(n - 1, r - 1);
unsigned char tmp = m_Digital_Array->at(n);
for (size_t j = n; j > 0; --j)
m_Digital_Array->at(j) = m_Digital_Array->at(j - 1);
m_Digital_Array->at(0) = tmp;
}
}
public: Permutation_nPr( const function<void(const shared_ptr<vector<unsigned char> > &, size_t)> &Receive ) :m_Report(Receive)
{}
void nPr(size_t n, size_t r)
{
m_r = r;
m_Digital_Array =
shared_ptr<vector<unsigned char> >(new vector<unsigned char>(n));
size_t i = n;
while (i--)
{
m_Digital_Array->at(i) = i;
}
v(n - 1, r - 1);
}
};
int N = 1;
void Show(const shared_ptr<vector<unsigned char> > &Digital_Array, size_t r)
{
cout << N << ":\t";
for (size_t i = Digital_Array->size() - 1; r > 0; --i, --r)
cout << (int)Digital_Array->at(i) << ' ';
cout << endl;
++N;
}
int main()
{
Permutation_nPr P(Show);
cout << "4P3 排列:" << endl;
N = 1;
P.nPr(4, 3);
return 0;
}
2018年3月14日 星期三
n 取 n 逆時鐘旋轉排列法
#include <functional> // std::function
#include <memory> // std::shared_ptr
#include <vector>
#include <iostream>
using namespace std;
// n 取 n 做排列
// 採用逆時旋轉排列法
class Permutation_nPn
{
// 回報結果
function<void(const shared_ptr<vector<unsigned char> > &)> m_Report;
// 放置要排的數字
shared_ptr <vector<unsigned char> > m_Digital_Array;
void v(size_t n)
{
if (n == 0)
m_Report(m_Digital_Array);
else
{
size_t i = n + 1;
while (i--)
{
v(n - 1);
unsigned char tmp = m_Digital_Array->at(n);
for (size_t j = n; j > 0; --j)
m_Digital_Array->at(j) = m_Digital_Array->at(j - 1);
m_Digital_Array->at(0) = tmp;
}
}
}
public: Permutation_nPn(
const function<void(const shared_ptr<vector<unsigned char> > &)>
&Receive
)
:m_Report(Receive)
{}
void nPn(size_t n)
{
m_Digital_Array = shared_ptr<vector<unsigned char> >(
new vector<unsigned char>(n));
size_t i = n;
while (i)
{
m_Digital_Array->at(i - 1) = i - 1;
--i;
}
v(n - 1);
}
};
int N = 1;
void Show(const shared_ptr<vector<unsigned char> > &Digital_Array)
{
cout << N << ":\t";
for (size_t i = Digital_Array->size(); i > 0; --i)
cout << (int)Digital_Array->at(i - 1) << ' ';
cout << endl;
++N;
}
int main()
{
Permutation_nPn P(Show);
cout << "4! 排列:" << endl;
N = 1;
P.nPn(4);
return 0;
}
2018年1月3日 星期三
2018年1月2日 星期二
Sprintf 簡單風格字串格式化
用於處理字串格式化的小工具,可指定參數在字串中的插入位置。
範例:
stringstream ss;
Sprintf(ss, "我搭{1}去{0}。", "台北", "火車");
{0} = 第一個參數
{1} = 第二個參數
...
若有錯誤回傳 false,表示指定的參數超過提供的數量範圍
下載:
SPRINTF_1_1_5.zip (內附範例)
範例:
stringstream ss;
Sprintf(ss, "我搭{1}去{0}。", "台北", "火車");
{0} = 第一個參數
{1} = 第二個參數
...
若有錯誤回傳 false,表示指定的參數超過提供的數量範圍
下載:
SPRINTF_1_1_5.zip (內附範例)
2018年1月1日 星期一
TlcMultiple 小工具程式原碼
用於處理 CxxlMan2 函數庫 TLC 文件的同名項目的小工具。
最好的處理方式是 匯入->排序->匯出,以人工方式處理標示同名的項目。
除非確定自動刪除同名項目不會有問題,否則請小心使用 MultipleClear() 功能
下載:
TlcMultiple_1_0_0.zip
使用範例:
先安裝好 CxxlMan2 函數庫,以下是使用範例
最好的處理方式是 匯入->排序->匯出,以人工方式處理標示同名的項目。
除非確定自動刪除同名項目不會有問題,否則請小心使用 MultipleClear() 功能
下載:
TlcMultiple_1_0_0.zip
使用範例:
先安裝好 CxxlMan2 函數庫,以下是使用範例
訂閱:
文章 (Atom)