QZhong C++ Style
Write compact, mathematically legible C++ with reusable typed components,
convenient public APIs, and explicit control over storage and computation.
Put flexibility in types and overloads while keeping the numerical algorithm
visible as ordinary expressions and loops.
Resolve the context first
Read the target's applicable instructions, language standard, formatter, and a
nearby interface and implementation. Follow explicit task/repository rules
first, then the conventions of the code being edited, then these defaults.
Use cuMES's explicit naming and ownership rules as defaults for new code.
Do not rename established APIs or modernize an entire file just to match them.
BSplineInterpolation supports C++11; cuMES requires strict C++20. Use the
target's standard. On C++20 targets, express new constraints with
concepts/requires or simple traits when appropriate; preserve SFINAE and
compatibility guards in older libraries. Do not add polyfills to modern targets
merely because the source projects contain them.
For evidence, exceptions, or an explanation of the user's style, read
references/style-evidence.md. Ordinary use does
not require reopening the original projects.
Names and surface form
- Use
PascalCase for types, snake_case for functions and variables, and
CAPITAL_SNAKE_CASE for constants and scoped-enum enumerators in new APIs.
Keep established mathematical/physics names such as psi, dpdr, rmnc,
ns, nZnT, and jF. Do not expand clear formulas into verbose prose names.
- Put
using val_type = T; first in the public section of scalar-templated
classes/structs. Give other roles descriptive aliases such as coord_type,
size_type, matrix_type, and error_type. Derive aliases from component
types rather than repeating concrete types. Do not invent a scalar alias
for a template with no scalar role, such as CLAP<Config>.
- Prefer trailing underscores for private data in new classes. Private helper
suffixes such as
build_solver_ occur frequently; follow neighboring code
rather than requiring a suffix for every private function. Plain data structs
can expose named fields directly.
- Use the existing
.clang-format. The shared baseline is Chromium, four-space
indentation, 80 columns, attached braces, and short if/loop/block bodies
allowed on one line. Small accessors like size() const { return size_; }
and guards like if (empty()) { return; } fit the style.
- Wrap long templates, signatures, initializer lists, and formulas with the
formatter's continuation alignment. Keep
T*/T& spelling and include
grouping consistent with the target. Include order differs between the old
libraries and cuMES; there is no universal personal include order.
- For a new project without a formatter, use
assets/clang-format as a
.clang-format starting point.
Do not replace an existing configuration or reformat unrelated code.
Types, APIs, and decomposition
- Parameterize genuinely variable scalar types, dimensions, orders, and
callable policies. Use fixed-size
std::array when the shape is known at
compile time. Keep one source of truth for precision and derive downstream
types from it; distinct coordinate/value/accumulation types can be intentional.
- Prefer concrete composition, function templates, and callable parameters for
numerical customization. Small lambdas should express the user's field
formula at the call site. Use traits to derive output shape when useful.
CRTP fits a shared implementation with real static specializations; it is
an available technique, not a requirement for every class.
- Provide a clear core operation and a few useful convenience forms. Delegate
constructors/overloads to one implementation. Examples are coordinate-array
plus variadic overloads,
operator() for a mathematical callable, and solve
backed by solve_in_place.
- Where both access modes are useful, distinguish ordinary evaluation from an
explicitly checked form such as
at/derivative_at. Document preconditions;
do not add duplicate checks to every layer of a numerical hot path.
- Keep configuration, raw input, reusable computation, and output representation
distinguishable. Use small structs for coherent values and owning classes
for reusable state. Avoid introducing interface hierarchies, factories, or
extra modules without a concrete variation or ownership need.
- Header-only template libraries and small single-header utilities are natural
here. Keep non-template implementation in source files when that is the
target's pattern. Do not force cuMES's explicit-instantiation layout onto a
standalone CPU library.
Ownership and cost
- Use values and RAII ownership. Prefer
std::vector/std::array for storage,
references for objects, and std::span/std::string_view for borrowed data
when the language standard permits. In new host APIs, use
std::optional<std::reference_wrapper<T>> for a nullable borrowed object
where appropriate. Preserve iterator-range APIs in compatible libraries.
- Keep raw pointers at necessary interop/device boundaries. In CUDA code use
the project's buffer/arena owners and typed views; retain
d_/h_ pointer
prefixes where applicable. Old pointer arithmetic in clap.h is not a model
for new ownership or reflection code.
- Separate expensive setup from repeated work when reuse exists: build/factor
once, solve/evaluate many times; cache coordinate-dependent work separately
from changing field values. Reserve known capacities and reuse scratch where
it matters. Do not add a cache or allocator without a demonstrated use.
- Pass read-only containers by const reference or view. Move owned storage into
an object; use forwarding references only when forwarding serves the API.
Return local values normally to allow copy elision. Preserve meaningful
const&/&& overloads for reuse versus consumption.
- Keep memory layout and loop order explicit. Flat contiguous storage and
dimensional wrappers recur, but BSpline Mesh is row-major and cuMES uses
column-major layouts: honor the algorithm's actual contract.
Numerical implementation and diagnostics
- Write recognizable formulas and direct loops. Use short local lambdas for
nearby transformations,
auto for obvious or complicated derived types,
and explicit scalar/index types when precision or signedness matters.
Prefer named intermediates when a conditional or expression becomes hard to
read; compact code need not become a dense nested ternary.
- Use
const, constexpr, explicit conversions, and typed zero initialization
where their meaning is useful. Keep precision conversions deliberate; do not
change accumulation type or floating-point evaluation order as a style edit.
- Use compile-time checks for type/shape constraints, runtime validation for
external input, and assertions for internal invariants, following the target's
error mechanism. Diagnostics should identify the offending value/option and
the expected condition. Do not copy old unchecked parsing behavior.
- Macros are acceptable for an existing registration DSL, configuration switch,
or compatibility boundary. The preference shown by clap.h is concise typed
registration at the call site; macros and byte offsets are not universal
implementation requirements.
- Comment mathematical meaning, units, ordering, boundary/periodicity
conventions, and non-obvious lifetime or performance decisions. Short section
comments can mark algorithm stages. Use concise Doxygen documentation for
public templates when neighboring code does, without narrating every statement.
Verification
Use the project's checks. For numerical changes, favor observable mathematical
properties, analytic cases, residuals, or CPU-reference comparisons, including
relevant precision and boundary cases. The source projects favor standalone
test executables with lightweight assertions; do not introduce a test framework
just for a small addition. Keep correctness checks separate from timing claims.
In cuMES, consult its current verification rules before a numerical refactor:
the frozen trajectory and controller decisions can be part of correctness.
Those gates, GPU-only execution, and allocation-at-startup requirements are
project contracts, not universal C++ preferences.
1---2name: qzhong-cpp-style3description: Write, refactor, or review C++ and CUDA C++ in QZhong's personal style, inferred from BSplineInterpolation, mct/libmeq, clap.h, and the cuMES coding guide. Use for C++ implementation in QZhong's projects or requests to code like QZhong; preserve the target project's compatibility and local conventions.4---56# QZhong C++ Style78Write compact, mathematically legible C++ with reusable typed components,9convenient public APIs, and explicit control over storage and computation.10Put flexibility in types and overloads while keeping the numerical algorithm11visible as ordinary expressions and loops.1213## Resolve the context first1415Read the target's applicable instructions, language standard, formatter, and a16nearby interface and implementation. Follow explicit task/repository rules17first, then the conventions of the code being edited, then these defaults.18Use cuMES's explicit naming and ownership rules as defaults for new code.19Do not rename established APIs or modernize an entire file just to match them.2021BSplineInterpolation supports C++11; cuMES requires strict C++20. Use the22target's standard. On C++20 targets, express new constraints with23concepts/requires or simple traits when appropriate; preserve SFINAE and24compatibility guards in older libraries. Do not add polyfills to modern targets25merely because the source projects contain them.2627For evidence, exceptions, or an explanation of the user's style, read28[references/style-evidence.md](references/style-evidence.md). Ordinary use does29not require reopening the original projects.3031## Names and surface form3233- Use `PascalCase` for types, `snake_case` for functions and variables, and34 `CAPITAL_SNAKE_CASE` for constants and scoped-enum enumerators in new APIs.35 Keep established mathematical/physics names such as `psi`, `dpdr`, `rmnc`,36 `ns`, `nZnT`, and `jF`. Do not expand clear formulas into verbose prose names.37- Put `using val_type = T;` first in the public section of scalar-templated38 classes/structs. Give other roles descriptive aliases such as `coord_type`,39 `size_type`, `matrix_type`, and `error_type`. Derive aliases from component40 types rather than repeating concrete types. Do not invent a scalar alias41 for a template with no scalar role, such as `CLAP<Config>`.42- Prefer trailing underscores for private data in new classes. Private helper43 suffixes such as `build_solver_` occur frequently; follow neighboring code44 rather than requiring a suffix for every private function. Plain data structs45 can expose named fields directly.46- Use the existing `.clang-format`. The shared baseline is Chromium, four-space47 indentation, 80 columns, attached braces, and short if/loop/block bodies48 allowed on one line. Small accessors like `size() const { return size_; }`49 and guards like `if (empty()) { return; }` fit the style.50- Wrap long templates, signatures, initializer lists, and formulas with the51 formatter's continuation alignment. Keep `T*`/`T&` spelling and include52 grouping consistent with the target. Include order differs between the old53 libraries and cuMES; there is no universal personal include order.54- For a new project without a formatter, use55 [assets/clang-format](assets/clang-format) as a `.clang-format` starting point.56 Do not replace an existing configuration or reformat unrelated code.5758## Types, APIs, and decomposition5960- Parameterize genuinely variable scalar types, dimensions, orders, and61 callable policies. Use fixed-size `std::array` when the shape is known at62 compile time. Keep one source of truth for precision and derive downstream63 types from it; distinct coordinate/value/accumulation types can be intentional.64- Prefer concrete composition, function templates, and callable parameters for65 numerical customization. Small lambdas should express the user's field66 formula at the call site. Use traits to derive output shape when useful.67 CRTP fits a shared implementation with real static specializations; it is68 an available technique, not a requirement for every class.69- Provide a clear core operation and a few useful convenience forms. Delegate70 constructors/overloads to one implementation. Examples are coordinate-array71 plus variadic overloads, `operator()` for a mathematical callable, and `solve`72 backed by `solve_in_place`.73- Where both access modes are useful, distinguish ordinary evaluation from an74 explicitly checked form such as `at`/`derivative_at`. Document preconditions;75 do not add duplicate checks to every layer of a numerical hot path.76- Keep configuration, raw input, reusable computation, and output representation77 distinguishable. Use small structs for coherent values and owning classes78 for reusable state. Avoid introducing interface hierarchies, factories, or79 extra modules without a concrete variation or ownership need.80- Header-only template libraries and small single-header utilities are natural81 here. Keep non-template implementation in source files when that is the82 target's pattern. Do not force cuMES's explicit-instantiation layout onto a83 standalone CPU library.8485## Ownership and cost8687- Use values and RAII ownership. Prefer `std::vector`/`std::array` for storage,88 references for objects, and `std::span`/`std::string_view` for borrowed data89 when the language standard permits. In new host APIs, use90 `std::optional<std::reference_wrapper<T>>` for a nullable borrowed object91 where appropriate. Preserve iterator-range APIs in compatible libraries.92- Keep raw pointers at necessary interop/device boundaries. In CUDA code use93 the project's buffer/arena owners and typed views; retain `d_`/`h_` pointer94 prefixes where applicable. Old pointer arithmetic in clap.h is not a model95 for new ownership or reflection code.96- Separate expensive setup from repeated work when reuse exists: build/factor97 once, solve/evaluate many times; cache coordinate-dependent work separately98 from changing field values. Reserve known capacities and reuse scratch where99 it matters. Do not add a cache or allocator without a demonstrated use.100- Pass read-only containers by const reference or view. Move owned storage into101 an object; use forwarding references only when forwarding serves the API.102 Return local values normally to allow copy elision. Preserve meaningful103 `const&`/`&&` overloads for reuse versus consumption.104- Keep memory layout and loop order explicit. Flat contiguous storage and105 dimensional wrappers recur, but BSpline Mesh is row-major and cuMES uses106 column-major layouts: honor the algorithm's actual contract.107108## Numerical implementation and diagnostics109110- Write recognizable formulas and direct loops. Use short local lambdas for111 nearby transformations, `auto` for obvious or complicated derived types,112 and explicit scalar/index types when precision or signedness matters.113 Prefer named intermediates when a conditional or expression becomes hard to114 read; compact code need not become a dense nested ternary.115- Use `const`, `constexpr`, explicit conversions, and typed zero initialization116 where their meaning is useful. Keep precision conversions deliberate; do not117 change accumulation type or floating-point evaluation order as a style edit.118- Use compile-time checks for type/shape constraints, runtime validation for119 external input, and assertions for internal invariants, following the target's120 error mechanism. Diagnostics should identify the offending value/option and121 the expected condition. Do not copy old unchecked parsing behavior.122- Macros are acceptable for an existing registration DSL, configuration switch,123 or compatibility boundary. The preference shown by clap.h is concise typed124 registration at the call site; macros and byte offsets are not universal125 implementation requirements.126- Comment mathematical meaning, units, ordering, boundary/periodicity127 conventions, and non-obvious lifetime or performance decisions. Short section128 comments can mark algorithm stages. Use concise Doxygen documentation for129 public templates when neighboring code does, without narrating every statement.130131## Verification132133Use the project's checks. For numerical changes, favor observable mathematical134properties, analytic cases, residuals, or CPU-reference comparisons, including135relevant precision and boundary cases. The source projects favor standalone136test executables with lightweight assertions; do not introduce a test framework137just for a small addition. Keep correctness checks separate from timing claims.138139In cuMES, consult its current verification rules before a numerical refactor:140the frozen trajectory and controller decisions can be part of correctness.141Those gates, GPU-only execution, and allocation-at-startup requirements are142project contracts, not universal C++ preferences.