r/cpp • • 7d ago

Misleading Token Sequence Injection & Modern Macros: The Most Game-Changing Compile-Time Feature in C++29 (Try it on Compiler Explorer with Barry's Clang Compiler!)

Thumbnail open-std.org
50 Upvotes

Note: This feature is targeted at the C++29 standard and is not actually included in the standard in the original language prepared for the publication. I didn't mention that it was a feature within the standard, and that was that. However, when I asked the AI to translate and organize the text, it made this incorrect edit to the title, thinking it was a good hoke. I apologize for this.

introduces Token Sequence Injection (std::meta::tokensequence) and Hygienic Language Macros (_macro) for C++29. It allows building, manipulating, and injecting C++ tokens at compile time with full type-awareness, context inspection, and zero preprocessor bugs!

. Token Sequence Injection (std::meta::token_sequence)

Instead of string manipulation or macro hacks, code is treated as a sequence of tokens stored in std::meta::token_sequence.

Acts as a random-access range (std::meta::size(seq), indexing seq[i] like array, concatenation +, += , == , =)

Features Token Interpolation (...) to splice expressions, variables, or types inside token literals { ... }.

Provides standard utilities like std::meta::id("arg", i) to generate unique identifiers, std::meta::tokenize to turns the string or array of chars to array of tokens with type std::meta::token_sequence, std::meta::stringize to turn array of tokens with type std::meta::token_sequence to string, and std::meta::queue_injection For indirect injection, such as injecting tokens into the current domain or a specific namespace.

Quick code example: ```

constexpr auto make_getter(std::meta::info member) -> std::meta::token_sequence {

auto name = std::meta::id("get_", name_of(member));

return {

auto (name)() const -> decltype((member)) {

return (member);

}

};

}

```

  1. Modern Hygienic Macros (__macro)

Replacing #define, the new __macro feature runs at consteval time and returns a std::meta::token_sequence injected directly at the call-site:

Invoked with !: Called as macro!(...) , check!(a == b).

Receives Expression Reflections: Arguments are passed as expression handles (std::meta::info), preserving expression identity, source text, and value categories.

Prevents Double Evaluation: Injecting the same un-stored expression twice is a compile-time safety violation, eliminating bugs like MIN(x++, y).

Context-Aware (macro_expansion_context()): Can inspect the caller's scope (enclosing function, class, or return type) to validate syntactic and logical rules before injecting.

Module & Namespace Friendly: Fully scoped, exportable in modules, and can be class/namespace members.

Quick code example :

```

template <class T> __macro check(T&&expr) {

return {

if (!((expr))) {

std::println("Check failed: {}", source_text_of(expr));

}

};

}

```

You can test the full implementation on Compiler Explorer today using Barry Revzin's Clang prototype fork!

Paper link: https://open-std.org/JTC1/SC22/WG21/docs/papers/2026/p4380r0.html

r/cpp • • Dec 21 '25

Misleading Constvector: Log-structured std:vector alternative – 30-40% faster push/pop

33 Upvotes

Usually std::vector starts with 'N' capacity and grows to '2 * N' capacity once its size crosses X; at that time, we also copy the data from the old array to the new array. That has few problems

  1. Copy cost,
  2. OS needs to manage the small capacity array (size N) that's freed by the application.
  3. L1 and L2 cache need to invalidate the array items, since the array moved to new location, and CPU need to fetch to L1/L2 since it's new data for CPU, but in reality it's not.

It reduces internal memory fragmentation. It won't invalidate L1, L2 cache without modifications, hence improving performance: In the github I benchmarked for 1K to 1B size vectors and this consistently improved showed better performance for push and pop operations.
 
Github: https://github.com/tendulkar/constvector

Youtube: https://youtu.be/ledS08GkD40

Practically we can use 64 size for meta array (for the log(N)) as extra space. I implemented the bare vector operations to compare, since the actual std::vector implementations have a lot of iterator validation code, causing the extra overhead.

Upon popular suggestion I tried with STL vector, and pop operations without deallocations, here are the results. Push is lot better, Pop is on par, iterator is slightly worse, and random access has ~75% extra latency.

Operation | N    | Const (ns/op) | Std (ns/op) | Δ %
------------------------------------------------------
Push      | 10   | 13.7          | 39.7        | −65%
Push      | 100  | 3.14          | 7.60        | −59%
Push      | 1K   | 2.25          | 5.39        | −58%
Push      | 10K  | 1.94          | 4.35        | −55%
Push      | 100K | 1.85          | 7.72        | −76%
Push      | 1M   | 1.86          | 8.59        | −78%
Push      | 10M  | 1.86          | 11.36       | −84%
------------------------------------------------------
Pop       | 10   | 114           | 106         | +7%
Pop       | 100  | 15.0          | 14.7        | ~
Pop       | 1K   | 2.98          | 3.90        | −24%
Pop       | 10K  | 1.93          | 2.03        | −5%
Pop       | 100K | 1.78          | 1.89        | −6%
Pop       | 1M   | 1.91          | 1.85        | ~
Pop       | 10M  | 2.03          | 2.12        | ~
------------------------------------------------------
Access    | 10   | 4.04          | 2.40        | +68%
Access    | 100  | 1.61          | 1.00        | +61%
Access    | 1K   | 1.67          | 0.77        | +117%
Access    | 10K  | 1.53          | 0.76        | +101%
Access    | 100K | 1.46          | 0.87        | +68%
Access    | 1M   | 1.48          | 0.82        | +80%
Access    | 10M  | 1.57          | 0.96        | +64%
------------------------------------------------------
Iterate   | 10   | 3.55          | 3.50        | ~
Iterate   | 100  | 1.40          | 0.94        | +49%
Iterate   | 1K   | 0.86          | 0.74        | +16%
Iterate   | 10K  | 0.92          | 0.88        | ~
Iterate   | 100K | 0.85          | 0.77        | +10%
Iterate   | 1M   | 0.90          | 0.76        | +18%
Iterate   | 10M  | 0.94          | 0.90        | ~