在 C++ 裡面,如果需要知道一個型別的資訊,基本上可以使用 typeid()
這個運算子(文件)來取得 std::type_info
(文件)的物件、然後他還有提供 name()
這個函式,可以用來取得型別的名稱。
所以,在一般的情況下,如果要知道一個型別的名稱,可以使用下面的形式來做:
#include <iostream> #include <tuple> int main() { std::cout << "float: " << typeid(float).name() << "\n" << "tuple: " << typeid(std::tuple<int, double>).name() << "\n" << std::endl; }
在 Visual Studio 的話,會輸出下面的結果,非常好閱讀。
float: float tuple: class std::tuple<int,double>
在特定的狀況下,這種資訊也是適合用來除錯、或是回報訊息給使用者的。
不過同樣的寫法如果換成是用 g++ 或 clang 的話,則是會出現下面的結果:
float: f tuple: St5tupleIJidEE
感覺上,變得相當難以理解了?
為什麼會這樣呢?這是因為這個函式回傳的結果基本上會是實作自己定義的(implementation defined),而 g++ 和 clang 選擇的方法是回傳「mangled name」的結果。
而他的處理方法,基本上就是去簡化名稱,像是 float
就變成 f
、std
變成 St
這樣;它會讓整個字串變得精簡,但是相對地也不適合人類閱讀。
而如果希望在 Linux 上可以讓結果變得像 Visual C++ 的結果一樣可以閱讀的話,可以在執行的時候搭配「c++filt」這個程式(說明)來使用。這邊比較適合的方法,是:
./a.out | c++filt -t
這樣把 ./a.out
的結果導向給 c++filt、並加上「-t
」讓他去處理型別,這樣就可以得到適合人類閱讀的結果了!
不過這是在執行的時候去處理,如果想在寫在程式裡面的話要怎麼辦呢?這邊可以使用 libstdc++ 的 demangling 功能(文件)來做,但是基本上就會變程式綁死平台的了。
所以如果要考慮跨平台的話,比較好的方法,或許是使用 Boost C++ Libraries 的功能了~
要使用也算滿簡單的,只要直接呼叫 boost::core::demangle()
這個函式(文件)、讓它處理名稱就可以了。
下面就是修改過的版本:
#include <iostream> #include <tuple> #include <boost/core/demangle.hpp> int main() { std::cout << "float: " << boost::core::demangle(typeid(float).name()) << "\n" << "tuple: " << boost::core::demangle(typeid(std::tuple<int, double>).name()) << "\n" << std::endl; }
這樣基本上就可以直接輸出人類看得懂的型別名稱了。