趁出去玩之前發一下文章,在C++ Reflection還沒正式定案之前,總有自救會想盡辦法來解決這些問題
Pre C++20
在C++20之前,最簡單的方法就是用Macro了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include <iostream>
#define PRINT_FIELD_NAME(struct_type, field) \ std::cout << #field << std::endl;
template <typename T> void printFieldNames(const T& obj) { }
#define SPECIALIZE_PRINT_FIELD_NAMES(struct_type, ...) \ template <> \ void printFieldNames<struct_type>(const struct_type& obj) { \ __VA_ARGS__ \ }
struct MyStruct { int field1; double field2; char field3; };
SPECIALIZE_PRINT_FIELD_NAMES(MyStruct, PRINT_FIELD_NAME(MyStruct, field1) PRINT_FIELD_NAME(MyStruct, field2) PRINT_FIELD_NAME(MyStruct, field3) )
int main() { MyStruct myObj; printFieldNames(myObj);
return 0; }
|
Macro的方案都差不多,不過問題是出在Macro,由於在Preprocessor階段,得不到C++2的語意,所以會遇上以下問題
接著就到了C++20時期了
Core knowledge
在這之前要先介紹一個核心知識,沒有這個都辦不到
1 2 3 4 5 6 7 8 9 10 11 12
| template<typename T> void test() { std::cout << __PRETTY_FUNCTION__ << '\n'; }
#include <source_location> template <typename T> void test() { std::cout << std::source_location::current().function_name() << "\n"; }
|
__PRETTY_FUNCTION__
是gcc/clang特有的,Visual C++有等價的__FUNCSIG__
,不過在C++20之後,用std::source_location::current().function_name()
就好,接下來的問題就變成了,如何將struct的information成為funcion name的一部分`
Non-type Template Parameters in C++20
在C++20當中,NTTP能居受的種類更多了,由於這樣,很難推斷出類型,所以template <auto>
發揮出功用了
1 2 3 4 5 6 7 8 9 10 11 12 13
| template <auto V> void test() { std::cout << std::source_location::current().function_name() << "\n"; }
struct obj { int field; };
int main() { test<&obj::field>(); } `
|
輸出結果
1
| void test() [with auto V = &obj::field]
|
到目前為止,這段程式碼還不是太有用,因為印出了太多不需要的東西,所以要對輸出Function Name做處理
Process Function Name
用constexpr std::string_view做處理
1 2 3 4 5 6 7 8 9 10 11
| template <auto V> constexpr std::string_view get_name() { std::string_view funcname = std::source_location::current().function_name(); auto pos = funcname.find("="); funcname = funcname.substr(pos); pos = funcname.find("::"); funcname = funcname.substr(pos + 2); pos = funcname.find(";"); return funcname.substr(0, pos); }
|
MSVC和gcc/clang的處理方式不同,要個別處理
Reference