From 994e500c4d503aeebb1f840846de25ab02566d0b Mon Sep 17 00:00:00 2001 From: Nakidai Date: Wed, 10 Jun 2026 06:19:14 +0300 Subject: [PATCH 1/2] Add C++ support To be portable across C and C++ cvector needs only a couple of changes where C++ needs explicit casts. A macro cvector_typeof is made to cast in C++ and do nothing in C and it is applied in needed places --- cvector.h | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/cvector.h b/cvector.h index 9be677d..1e8628b 100644 --- a/cvector.h +++ b/cvector.h @@ -62,6 +62,32 @@ typedef struct cvector_metadata_t { cvector_elem_destructor_t elem_destructor; } cvector_metadata_t; +/* C++ requires explicit casts between pointer types when C does not. + * cvector_typeof either does nothing since typeof in C was introduced + * too late (only in C23) and C can happily cast implicitly, or returns + * the type of a given expression depending on the language + */ +#ifdef __cplusplus +#include +/* When macros are used, arguments are often get enclosed in + * parentheses. When decltype() gets a parenthesized expression, it + * also makes the type a reference and C++ compiler complains about + * this during the cast. For this reason the reference part of the type + * should be manually stripped out + */ +/** + * @brief cvector_typeof - Return a type of the expression + * @param expr An expression to examine + */ +#define cvector_typeof(expr) std::remove_reference::type +#else +/** + * @brief cvector_typeof - Stub macro returning void * + * @param _ Stub parameter + */ +#define cvector_typeof(_) void * +#endif + /** * @brief cvector_vector_type - The vector type used in this library * @param type The type of vector to act on. @@ -407,11 +433,11 @@ typedef struct cvector_metadata_t { void *cv_grow_p1__ = cvector_vec_to_base(vec); \ void *cv_grow_p2__ = cvector_clib_realloc(cv_grow_p1__, cv_grow_sz__); \ cvector_clib_assert(cv_grow_p2__); \ - (vec) = cvector_base_to_vec(cv_grow_p2__); \ + (vec) = (cvector_typeof(vec))cvector_base_to_vec(cv_grow_p2__); \ } else { \ void *cv_grow_p__ = cvector_clib_malloc(cv_grow_sz__); \ cvector_clib_assert(cv_grow_p__); \ - (vec) = cvector_base_to_vec(cv_grow_p__); \ + (vec) = (cvector_typeof(vec))cvector_base_to_vec(cv_grow_p__); \ cvector_set_size((vec), 0); \ cvector_set_elem_destructor((vec), NULL); \ } \ From e25597a99ece13745e4aa9f1e8bf4d0c69e44825 Mon Sep 17 00:00:00 2001 From: Nakidai Date: Wed, 10 Jun 2026 22:45:57 +0300 Subject: [PATCH 2/2] Get rid of type traits std::remove_reference can be replaced with just taking an address of the first element --- cvector.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cvector.h b/cvector.h index 1e8628b..6f9c415 100644 --- a/cvector.h +++ b/cvector.h @@ -68,18 +68,17 @@ typedef struct cvector_metadata_t { * the type of a given expression depending on the language */ #ifdef __cplusplus -#include /* When macros are used, arguments are often get enclosed in * parentheses. When decltype() gets a parenthesized expression, it * also makes the type a reference and C++ compiler complains about - * this during the cast. For this reason the reference part of the type - * should be manually stripped out + * this during the cast. Taking an address of the first element removes + * the reference part */ /** * @brief cvector_typeof - Return a type of the expression * @param expr An expression to examine */ -#define cvector_typeof(expr) std::remove_reference::type +#define cvector_typeof(expr) decltype(&(expr)[0]) #else /** * @brief cvector_typeof - Stub macro returning void *