using L = std::tuple<void, int, float>; using R = mp_transform<std::add_pointer_t, L>; static_assert(std::is_same_v<R, std::tuple<void*, int*, float*>>);
可以用Meta Programming重寫
1 2 3 4 5 6 7 8 9 10 11
template < typename T> consteval auto transform(std::meta::info (&F)(std::meta::info)) -> std::meta::info { std::vector<std::meta::info> new_members; for (auto member : template_arguments_of(^^T)) { new_members.push_back(F(member)); } return substitute(template_of(^^T), new_members); } using L = std::tuple<void, int, float>; using R = [:transform<L>(std::meta::type_add_pointer):]; static_assert(std::is_same_v<R, std::tuple<void*, int*, float*>>);
Structure, union and enumeration types may be defined more than once in the same scope with the same contents and the same tag; if such types are defined with the same contents and the same tag in different scopes, the types are compatible.
以下的程式碼在C23是合法的
1 2 3 4 5 6 7
structA { int a; };
structA { int a; };
而在C23之前會被歸類成 redefinition of 'struct A' 有了這個,在C語言寫類Generic 會比較方便 例如
Result_t(int, ErrorMessage_t) my_func(int i) { if (i == 42) return Ok(int, ErrorMessage_t)(100); elsereturn Err(int, ErrorMessage_t)("Cannot do the thing"); }
intmain() { Result_t(int, ErrorMessage_t) x = my_func(42);
intmain(void) { // Get a 32-bit buffer from the system uint32_t* buff = malloc(sizeof(Msg)); // Alias that buffer through message Msg* msg = (Msg*)(buff); // Send a bunch of messages for (int i = 0; i < 10; ++i) { msg->a = i; msg->b = i+1; SendWord(buff[0]); SendWord(buff[1]); } }
Solution
C Solution
union
C語言的話可以使用union
1 2 3 4
union { Msg msg; unsignedint asBuffer[sizeof(Msg)/sizeof(unsignedint)]; };
structFooRc { bar: Rc<String>, } structFooArc { bar: Arc<String>, }
不過這當然沒什麼好說的
Macro solution
理論上辦得到,不過沒什麼優點
GAT Solution
我希望能寫成這樣
1
structFoo<P: Pointer> { bar: P<String>, }
這樣是編譯不會過的,有了GAT之後,可以寫成這樣
1 2 3 4 5 6 7
traitPointerFamily { typePointer<T>; } structRcFamily; // Just a marker type; could also use e.g. an empty enum structArcFamily; // Just a marker type; could also use e.g. an empty enum impl PointerFamily for RcFamily { typePointer<T> = Rc<T>; } impl PointerFamily for ArcFamily { typePointer<T> = Arc<T>; }
structFoo<P: PointerFamily> { bar: P::Pointer<String>, }
template <typename T, auto * ConstructFunction, auto * DestructFunction> structc_resource { using pointer = T *; using const_pointer = std::add_const_t<T> *; using element_type = T;
private: using Constructor = decltype(ConstructFunction); using Destructor = decltype(DestructFunction);
static_assert(std::is_function_v<std::remove_pointer_t<Constructor>>, "I need a C function"); static_assert(std::is_function_v<std::remove_pointer_t<Destructor>>, "I need a C function");
template <auto * CleanupFunction> structguard { using cleaner = decltype(CleanupFunction);
static_assert(std::is_function_v<std::remove_pointer_t<cleaner>>, "I need a C function"); static_assert(std::is_invocable_v<cleaner, pointer>, "Please check the function");