C++ Module 18
C++26 previews: reflection, contracts and safety interview questions
Interview questions on “C++26 previews: reflection, contracts and safety”: warm-ups, then what each harder question tests and how a good answer starts.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
How do you check in code whether the compiler supports a C++26 feature?
Answered in the lesson What is in C++26 and which compilers support it
-
Fresher to mid
Why can a std::meta::info value not be used when the program runs?
Answered in the lesson C++26 reflection basics: ^^ and splicing
-
Fresher to mid
What does template for do, and why can an ordinary for loop over a vector of reflections not do the same job?
Answered in the lesson C++26 reflection: enum names and serialisation
-
Fresher to mid
How is a C++26 annotation such as [[=Column("id")]] different from an attribute such as [[nodiscard]]?
Answered in the lesson C++26 annotations: generating code from structs
-
Fresher to mid
Name the four evaluation semantics of C++26 contracts, and say which call the violation handler and which stop the program.
Answered in the lesson C++26 contracts: pre, post and contract_assert
-
Mid
What does the [[indeterminate]] attribute do in C++26, and when is it worth using?
Answered in the lesson C++26 erroneous behaviour and library hardening
-
Fresher to mid
What is std::function_ref in C++26, and when would you choose it over std::function?
Answered in the lesson C++26 library previews: simd, function_ref and more
-
Fresher to mid
What is a sender in C++26 std::execution, and how is it different from a std::future?
Answered in the lesson C++26 std::execution: senders and receivers
-
Fresher to mid
What does pack indexing, Ts...[N], do in C++26, and what did code use before it?
Answered in the lesson Smaller C++26 language features you can use now
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Senior to staff
Your library is built with Apple clang on macOS and with GCC 16 on Linux, and its public headers are included by other teams. A colleague wants to use C++26 reflection now to print enum names in those headers. What do you decide, and how do you keep every build working?
- What it tests
- Judging feature support across toolchains, feature detection in public headers, fallbacks that stay in sync, and the cost a header imposes on the projects that include it.
- First step
- List who compiles the header: not only your two builds but every project that includes it, with its own compiler and flags. A header that needs a feature some of them lack breaks their builds, so the question becomes how the header behaves when reflection is missing, not only when it is present.
- Follow-ups
-
- Which macros does the header test, and why both?
- How do you stop the fallback and the reflection version from drifting apart?
- When do you delete the fallback?
From the lesson What is in C++26 and which compilers support it
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A header checks that __cpp_lib_saturation_arithmetic is defined and then calls std::add_sat. It builds with Apple clang 21 but fails with GCC 16.2, although GCC defines the macro too. Explain why, and write a check that builds on both.
- What it tests
- What a feature-test macro's value means, revisions of a feature with different interfaces, and writing portable checks instead of testing only whether a macro exists.
- First step
- Print the macro's value on both compilers instead of asking whether it is defined. If the two values differ, the two libraries implement different revisions of the feature, and the function names can differ between revisions.
- Follow-ups
-
- Where would you look up the names each revision uses?
- Why not test the compiler, for example __GNUC__, instead?
- How do you keep this check out of the rest of the code base?
From the lesson What is in C++26 and which compilers support it
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A generic logger prints every data member of any struct by reflection, using nonstatic_data_members_of with access_context::unchecked(). A security audit flags it before release. What is the risk, and how do you change the logger and its tests?
- What it tests
- Access contexts in reflection, private data in logs, safe defaults for generic code, and how to test that a field is never printed.
- First step
- Ask which members unchecked() returns for a class with private data, such as a password hash or a token, and where the log lines end up: files, log services and support tickets, read by many more people than the code's authors.
- Follow-ups
-
- Which access context should the logger use, and from where?
- How do you hide a public member that must still never be logged?
- How do you test the rule so a future change cannot break it?
From the lesson C++26 reflection basics: ^^ and splicing
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A serialiser writes each object's type name, taken from display_string_of, into saved files, and checks it again when loading. All tests pass with GCC 16. What can go wrong in the field, and what would you store instead?
- What it tests
- The difference between identifier_of and display_string_of, implementation-defined output, and choosing stable identifiers for file formats.
- First step
- Look at what display_string_of returns for a std::string member and for a template specialisation, and ask who decides that text: the C++ standard, or each compiler and standard library.
- Follow-ups
-
- Is identifier_of a safe replacement everywhere?
- What changes when a type is renamed or moved to another namespace?
- How do you migrate files that already contain display strings?
From the lesson C++26 reflection basics: ^^ and splicing
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior
A unit test checks that a serialiser covers every field: it compares the number of fields written with nonstatic_data_members_of(^^T, unchecked()).size(). For a class that derives from another, the test passes while a field is missing from the output. Why, and how do you fix the test?
- What it tests
- What member queries return, inherited members and bases, and writing reflection-based checks that cover a whole object.
- First step
- Write down which members nonstatic_data_members_of returns for a derived class: only those the class declares itself, or also those of its bases? Then compare that with what the serialiser writes.
- Follow-ups
-
- How do you count every field of an object, bases included?
- What about virtual bases and empty bases?
- Which other members does the count leave out?
From the lesson C++26 reflection basics: ^^ and splicing
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
You are writing string_to_enum for enums read from configuration files that people edit by hand. What should it return for unknown text, how do you handle case and old names, and what changes for enums whose values are combined as bit flags?
- What it tests
- Designing a parsing interface, error reporting, compatibility with old input, and the limits of enumerators_of for flag enums.
- First step
- Separate the two questions: what the function returns, and what the program does with a bad line in a file. Start with the signature, because it decides whether a caller can forget to handle unknown text.
- Follow-ups
-
- Why not return a default enumerator for unknown text?
- How would you support a renamed enumerator without breaking old files?
- How do you print a combination such as read | write?
From the lesson C++26 reflection: enum names and serialisation
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
Inside a function, code stores the result of std::define_static_array, the list of a struct's members, in a local constexpr variable and loops over it with template for. GCC 16 rejects it with an error about the variable's address. Is the code wrong? Explain, and give two fixes.
- What it tests
- How an iterating expansion statement uses its range, constant expressions and addresses of local variables, and telling a compiler limitation from a language rule.
- First step
- Notice that the error is about an address, not a value. Ask what the expansion statement does with the variable you give it: does it copy the value, or bind a reference to it?
- Follow-ups
-
- Why does the same code compile when the call is written inside the template for?
- How would you check whether the final draft accepts the original code?
- Does adding static change the program's behaviour?
From the lesson C++26 reflection: enum names and serialisation
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
You maintain a logging library used by teams on GCC 16, Apple clang and MSVC. You want enum values in log lines to print as names. How do you design this so it works on every compiler today and improves as compilers add reflection?
- What it tests
- Feature detection, extension points for user types, fallbacks, compile-time cost, and an upgrade path that does not break users.
- First step
- Decide what the library promises on a compiler without reflection, because that is where most users are today. Then design one extension point that both the reflection path and the fallback can serve.
- Follow-ups
-
- What do users of compilers without reflection have to write?
- How do you test both paths in one continuous integration run?
- What happens to enums with thousands of enumerators?
From the lesson C++26 reflection: enum names and serialisation
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A colleague writes struct Label { std::string_view text; }; and annotates members with [[=Label{"price"}]]. GCC 16 rejects it. Explain the error, and give two designs that work, with their trade-offs.
- What it tests
- What a structural type is, why annotation values must be constants that could be template arguments, and choosing between text stored by pointer and text stored inline.
- First step
- Read GCC's note: it names the member whose type is not structural. Then check what structural requires of a class type's members, and look at how std::string_view's members are declared.
- Follow-ups
-
- Why is a plain const char* member not a fix either?
- What can go wrong when the text is stored in a char array instead?
- Can an annotation hold a std::string?
From the lesson C++26 annotations: generating code from structs
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
Design an annotation-driven CSV export for order records: column names, amounts stored in paise but written in rupees, fields that must never be exported, and correct quoting. What goes in annotations, what in the writer, and how do you test it?
- What it tests
- Separating data description from behaviour, formats, safe defaults for sensitive fields, standards compliance and testing with an independent reader.
- First step
- Decide the default for a member with no annotation: exported or not. That one decision determines whether a new field added next year leaks into every file.
- Follow-ups
-
- How do header and rows stay in the same column order?
- Where does quoting live, and which rules apply?
- How do you test that the files are readable by other programs?
From the lesson C++26 annotations: generating code from structs
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
After a team adopted reflection-generated serialisers, the clean build of a 200-file target went from 6 to 9 minutes. How do you find where the time goes, and how do you bring it down without giving up the generated code?
- What it tests
- Measuring compile time, separating fixed costs from per-type costs, instantiation control, and keeping reflection cheap in large code bases.
- First step
- Measure before changing anything: time the build per file and find the files whose time grew. Then split each such file's time into what any file pays, such as parsing headers, and what the generated code adds.
- Follow-ups
-
- Which compiler options show where a file's time goes?
- How do you stop every file from instantiating the same serialisers?
- When is code generated by a script the better choice?
From the lesson C++26 annotations: generating code from structs
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
You want to add preconditions to a function that 400 call sites use, and some callers may already break them. How do you introduce the contracts without crashing production, and how do you decide when to switch to enforce?
- What it tests
- Evaluation semantics as a rollout tool, violation handlers that log, measuring violations, and the risks of continuing after a broken precondition.
- First step
- Separate finding the violators from stopping them. A semantic that reports violations without changing behaviour lets you learn which callers break the contract before anything stops.
- Follow-ups
-
- What should the violation handler record?
- What is still dangerous while the contracts are only observed?
- How do you handle callers you cannot fix quickly?
From the lesson C++26 contracts: pre, post and contract_assert
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A function debits a wallet: debit(account_id, amount_paise). Which conditions belong in preconditions, which in a contract_assert, and which in an exception or an error result? Give one example of each and justify the choice.
- What it tests
- Telling programming errors from expected failures, choosing between contracts, exceptions and std::expected, and designing an interface around that choice.
- First step
- For each condition, ask who causes it when it fails: a bug in the caller, a bug in this function, or the world, such as a customer whose balance is too low. Only the first two are contract material.
- Follow-ups
-
- Is "the account exists" a precondition?
- What happens to a precondition when contracts are built with ignore?
- Where does a postcondition help here?
From the lesson C++26 contracts: pre, post and contract_assert
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
Your builds enforce contracts, and enforce stops the program on a violation. How do you write unit tests that prove a precondition actually fires?
- What it tests
- Violation handlers in tests, exceptions and noexcept, testing in a separate process, and keeping test-only behaviour out of production builds.
- First step
- A test runner cannot survive the program stopping, so either the violation must become something the test can catch, or the violation must happen in a process other than the test runner.
- Follow-ups
-
- What goes wrong with a throwing handler and noexcept functions?
- How do you test a contract while compiling?
- How do you stop the test handler from reaching production?
From the lesson C++26 contracts: pre, post and contract_assert
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A pull request contains bool allowed; if (user.is_admin()) allowed = true; return allowed;. The author says C++26 makes this safe, because reading an uninitialised variable is no longer undefined behaviour. Is that true with GCC 16 and Clang 21? What do you change in the code and in the build?
- What it tests
- Erroneous behaviour against undefined behaviour, what optimisers do with a missing store, and which warnings and builds catch it.
- First step
- Separate the language rule from what the build does. The C++26 rule says a non-admin's read gives the erroneous value, zero on GCC 16, so the function should return false. Then check what the optimised build really returns and whether any warning fired, because GCC's manual says it still optimises such a variable as if it were uninitialised.
- Follow-ups
-
- Would a test suite built at -O0 catch this bug?
- Which compiler warns about this, and with which option?
- Would -ftrivial-auto-var-init=zero fix it on both compilers?
From the lesson C++26 erroneous behaviour and library hardening
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to staff
Your team wants standard library hardening in a latency-sensitive service that ships a macOS build with Apple clang and libc++ and a Linux build with GCC and libstdc++. Which modes do you choose, how do you measure the cost, and how do you roll it out?
- What it tests
- The hardening modes of both libraries, measuring check cost where it matters, and a rollout that stops on violations without surprising the people on call.
- First step
- Start in tests, not in production: turn on libc++'s debug mode and _GLIBCXX_ASSERTIONS in every CI build and fix what they find. Then choose libc++'s fast mode and libstdc++'s assertions for release builds, and measure the hot loops before and after the switch.
- Follow-ups
-
- What does GCC's -fhardened do on the macOS build?
- How can code tell whether hardening is on?
- What should the people on call look for after the release?
From the lesson C++26 erroneous behaviour and library hardening
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
After turning on libc++'s fast hardening mode, a micro-benchmark that sums data[order[i]] over shuffled indexes got much slower, while every loop that walks data in order kept its speed. Explain both results, and say what you would do about the slow loop.
- What it tests
- How bounds checks interact with the optimiser, reading a micro-benchmark honestly, and fixing a hot loop without giving up the safety.
- First step
- Look at both loops from the optimiser's side: ask what it can prove about each index before the access, and what that means for the check that hardening adds there. Then ask how large a share of the slow loop's body one check is.
- Follow-ups
-
- Is a much slower loop a reason to switch hardening off?
- How would you check the indexes once instead of on every access?
- Why does a whole service lose far less than this loop?
From the lesson C++26 erroneous behaviour and library hardening
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
Design a queue of pending callbacks for an audio thread that runs hundreds of times a second and must never allocate, in C++26. Which types do you use, what breaks first under load, and what do you ship for a platform whose standard library lacks them?
- What it tests
- Allocation behaviour of callable wrappers and containers, non-owning lifetimes, capacity policy when full, and a portable fallback behind feature-test macros.
- First step
- Separate storage from ownership. Store the callbacks in std::inplace_vector, so the queue's memory lives inside the object, and as std::function_ref, so each entry is two pointers and nothing is copied or allocated; then state who owns each callable and decide what post() does when the queue is full.
- Follow-ups
-
- Why not std::vector with reserve() and std::function?
- What happens when a callback is destroyed while still queued?
- How do you test the zero-allocation promise?
From the lesson C++26 library previews: simd, function_ref and more
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A class keeps its implementation behind a std::unique_ptr, and the team now wants it copyable. When would you switch the member to std::indirect or std::polymorphic instead of writing a copy constructor, and what does a moved-from object look like?
- What it tests
- Value semantics against pointer semantics, deep copy, const propagation, the valueless state after a move, and incomplete types in a pimpl.
- First step
- Ask what a copy of the class should mean. If two copies must be independent, the member is a value that happens to live on the heap, which is what std::indirect is for one type and std::polymorphic for a hierarchy; then check what that choice gives the class's copy operations and its const member functions.
- Follow-ups
-
- Does std::indirect work when the type is incomplete in the header?
- What can you do with an object after std::move?
- When is std::shared_ptr the better member?
From the lesson C++26 library previews: simd, function_ref and more
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Senior to staff
Your team wants C++26 std::simd in a numeric library that ships on x86-64 Linux and on Apple silicon. What works today with GCC 16 and Apple clang 21, and how do you structure the code so that every platform gets vector code?
- What it tests
- Current implementation status, feature-test macros against target conditions, the Parallelism TS as a stand-in, floating-point ordering, and testing each branch.
- First step
- Start from the platforms, not the standard: GCC 16 declares std::simd only when the target has SSE2, Apple's libc++ has no <simd> header, and GCC 16 still ships the Parallelism TS 2 types for arm64. So the design is one thin wrapper with three back ends and tests that run all of them.
- Follow-ups
-
- Why does a plain float sum not vectorise on its own?
- How do you test that every back end gives the same results?
- What changes when Clang's library ships std::simd?
From the lesson C++26 library previews: simd, function_ref and more
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A service starts I/O with callbacks that capture request state by reference, and crashes under load point at stack memory of functions that have returned. How would std::execution and structured concurrency change the design, and what does the change cost?
- What it tests
- Lifetime reasoning for asynchronous code, structured concurrency with sync_wait and counting scopes, and an honest account of build cost and adoption risk.
- First step
- Reproduce it first, under AddressSanitizer, so that the report names the callback and the stack frame it touches. Then name the real bug: nothing ties the captured state's lifetime to the work, so any fix has to make the request's scope outlive its work.
- Follow-ups
-
- Where does the captured state live in the sender version?
- What happens if someone forgets to join a counting scope?
- What do you tell the team about build times?
From the lesson C++26 std::execution: senders and receivers
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A when_all joins three senders: a cache read, a database read and a remote call. The database read throws. Explain what happens to the other two, what sync_wait returns or throws, and how you would return the partial results instead.
- What it tests
- The three completion channels, how when_all reacts to an error, stop tokens, and recovering with upon_error.
- First step
- Follow the channels one at a time: what the throwing read becomes, what when_all then does with its other two children and with its own completion, and what sync_wait does with that completion in the calling thread.
- Follow-ups
-
- Does the remote call really stop?
- How do you return the two results that succeeded?
- What changes if a child completes with stopped instead of an error?
From the lesson C++26 std::execution: senders and receivers
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Senior to staff
Your team wants to use std::execution now, before GCC's or Apple's standard library ships it. Would you adopt stdexec or wait? If you adopt it, how do you contain the dependency so that the move to the standard library is cheap?
- What it tests
- Weighing a pre-standard dependency, one include point, keeping non-standard extras out of interfaces, build cost, and CI for both branches.
- First step
- Separate the interface from the implementation. stdexec's algorithms already have their C++26 names, so code written against them carries over; what remains is to find the parts of stdexec that will not carry over, and to contain them and the dependency itself.
- Follow-ups
-
- Which stdexec names have no C++26 equivalent?
- How do you keep build times under control?
- When would you wait instead?
From the lesson C++26 std::execution: senders and receivers
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
A caller passes 0.5 to set_timeout_ms(long), meaning half a second, and gets a timeout of 0 ms. How do you make such calls fail at compile time with a clear message in C++26, and how does that compare with what C++23 offered?
- What it tests
- Overload resolution with deleted functions, the C++26 deletion reason, alternatives such as strong types and constrained templates, and writing messages for the caller.
- First step
- Name the bug first: a double argument converts silently to long, so 0.5 becomes 0. Then make the conversion impossible to choose: declare set_timeout_ms(double) = delete("..."), which wins overload resolution for a double and turns the call into an error that, in C++26, shows the reason you wrote.
- Follow-ups
-
- What about float, long double or an int argument?
- Why not take a std::chrono::milliseconds instead?
- Can the reason be a constexpr string built from other text?
From the lesson Smaller C++26 language features you can use now
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Senior to staff
Your team moves a large C++23 code base to -std=c++26 with Apple clang 21 and GCC 16. What breaks first, how do you find it across the whole code base, and how do you keep both modes building during the transition?
- What it tests
- Knowing what C++26 removes, using warnings and two compilers to find it, feature-test macros, and planning a staged migration.
- First step
- Most of what breaks was already deprecated, so the first step is a C++23 build with -Wall on both compilers that fixes every deprecation warning. Then add a C++26 job beside the C++23 one.
- Follow-ups
-
- Why is one compiler not enough?
- Which changes give no diagnostic at all?
- How do you adopt the new features while C++23 builds must still pass?
From the lesson Smaller C++26 language features you can use now
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
Compare three ways to get the N-th type of a template parameter pack: a recursive template, std::tuple_element_t and C++26 pack indexing. Which would you use in a library today, and how would you measure the difference?
- What it tests
- How each technique works inside, compile-time cost and template depth limits, diagnostics, and portability across standards and compilers.
- First step
- Describe what each technique asks the compiler to do for one lookup, then measure instead of guessing: time syntax-only compiles of many lookups into a large pack, with both compilers.
- Follow-ups
-
- What happens with 1,100 types?
- How do you support C++23 and C++26 in one header?
- Which of the three gives the best error message for a bad index?
From the lesson Smaller C++26 language features you can use now
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes