Inspect
The inspect API provides deep, structured inspection tools for C++ values.
It is designed for debugging, diagnostics, type exploration, container analysis, and development-time visibility.
#include <vix/inspect.hpp>
int main()
{
vix::inspect(42);
vix::inspect(std::vector<int>{1, 2, 3});
vix::inspect_type<std::vector<int>>();
return 0;
}Header
#include <vix/inspect.hpp>Some projects may expose the API through a broader Vix include:
#include <vix.hpp>For direct usage, prefer:
#include <vix/inspect.hpp>What inspect does
vix::inspect renders a value with debugging-oriented information.
Compared to vix::print, inspect is more diagnostic.
Use print when you want simple output:
vix::print("user", 42);Use inspect when you want to understand a value, a type, a container, a struct, or a runtime state:
vix::inspect(std::vector<int>{1, 2, 3});
vix::inspect_type<std::vector<int>>();
vix::inspect_container(std::vector<int>{1, 2, 3});Basic usage
#include <vix/inspect.hpp>
#include <vector>
#include <string>
int main()
{
vix::inspect(42);
vix::inspect(true);
vix::inspect(std::string{"hello"});
vix::inspect(std::vector<int>{1, 2, 3});
return 0;
}Output shape:
42
true
"hello" [len=5]
[1, 2, 3] [n=3]The exact output can vary depending on options such as show_type, compact, and max_items.
Inspect vs print
| API | Purpose |
|---|---|
vix::print | Simple readable output. |
vix::inspect | Debugging-oriented value inspection. |
vix::inspect_type | Type metadata inspection. |
vix::inspect_meta | Value plus type metadata. |
vix::inspect_tree | Tree view for nested structures. |
vix::inspect_bytes | Raw byte dump for trivially copyable values. |
vix::inspect_numeric | Numeric range statistics. |
Use inspect while debugging.
Use print for simple developer output.
Use log for production logs.
Public API overview
| API | Purpose |
|---|---|
vix::inspect(value) | Inspect a value to stdout. |
vix::inspect(value, opts) | Inspect a value with custom options. |
vix::inspect_to(os, value) | Inspect a value to a specific stream. |
vix::inspect_to_string(value) | Return inspection output as a string. |
vix::inspect_type<T>() | Inspect type metadata for T. |
vix::inspect_type(value) | Inspect the deduced type of a value. |
vix::inspect_line(...) | Inspect multiple values on one line. |
vix::inspect_value(label, value) | Inspect a named value. |
vix::inspect_all(...) | Inspect multiple values, one per line. |
vix::inspect_meta(value) | Inspect value and full type metadata. |
vix::inspect_compact(value) | Return compact inspection string. |
vix::inspect_verbose(value) | Inspect with type tags, metadata, and addresses. |
vix::inspect_report(obj) | Detailed report for field_map structs. |
vix::inspect_container(c) | Container size, capacity, value type, elements. |
vix::inspect_bytes(value) | Hex dump of raw object bytes. |
vix::inspect_diff(a, b) | Compare two values side by side. |
vix::inspect_check(label, expected, actual) | Print PASS or FAIL check. |
vix::inspect_tap(value) | Inspect and return the same value. |
vix::inspect_if(condition, value) | Inspect only when condition is true. |
vix::tap_with(value, fn) | Run a callback and return the same value. |
vix::inspect_numeric(range) | Numeric range statistics and histogram. |
vix::inspect_tree(value) | Visual tree representation. |
vix::inspect_path<T>() | Return the selected inspection path. |
vix::inspect_paths<Ts...>() | Print inspection paths for many types. |
inspect_options
inspect_options controls how inspection is rendered.
vix::inspect_options opts;
opts.show_type = true;
opts.max_depth = 4;
opts.max_items = 10;
vix::inspect(std::vector<int>{1, 2, 3}, opts);Fields
| Field | Default | Purpose |
|---|---|---|
max_depth | 8 | Maximum recursive nesting depth. |
max_items | 64 | Maximum items per container. |
show_type | true | Show type annotations when supported. |
show_meta | false | Enable full metadata mode for verbose use. |
compact | false | Use compact single-line output. |
show_address | false | Show or follow object addresses when supported. |
indent_str | " " | Indentation unit. |
out | &std::cout | Output stream. |
Default options
default_options() returns the thread-local default inspection options.
auto &opts = vix::default_options();
opts.show_type = true;
opts.max_items = 20;
opts.max_depth = 5;
vix::inspect(std::vector<int>{1, 2, 3});Because the default options are thread-local, changing them affects the current thread.
Scoped options
Use scoped_inspect_options to temporarily override options.
vix::inspect(std::vector<int>{1, 2, 3});
{
vix::scoped_inspect_options guard{};
guard.opts.compact = true;
guard.opts.show_type = false;
vix::inspect(std::vector<int>{1, 2, 3});
}
vix::inspect(std::vector<int>{1, 2, 3});When the guard is destroyed, the previous options are restored.
Inspect a value
vix::inspect(42);
vix::inspect("hello");
vix::inspect(std::vector<int>{1, 2, 3});Inspect with custom options
vix::inspect_options opts;
opts.show_type = false;
opts.compact = true;
opts.max_items = 3;
vix::inspect(std::vector<int>{1, 2, 3, 4, 5}, opts);Output shape:
[1, 2, 3, ...]Inspect to a stream
std::ostringstream out;
vix::inspect_to(out, std::vector<int>{1, 2, 3});
std::string result = out.str();Inspect to string
std::string s = vix::inspect_to_string(std::vector<int>{1, 2, 3});
vix::print(s);Compact inspection
inspect_compact returns a compact string.
auto s = vix::inspect_compact(
std::map<std::string, int>{{"a", 1}, {"b", 2}}
);
vix::print(s);Output shape:
{a: 1, b: 2}Inspect several values on one line
int a = 1;
int b = 2;
int c = 3;
vix::inspect_line(a, b, c);Output shape:
1 | 2 | 3Inspect named values
int batch_size = 64;
vix::inspect_value("batch_size", batch_size);Output:
batch_size: 64Inspect multiple values
vix::inspect_all(
std::string{"hello"},
42,
3.14,
std::vector<int>{1, 2, 3}
);Each value is inspected on its own line.
Supported types
inspect supports the same broad type categories as the Vix rendering engine, with extra diagnostic information.
| Type category | Examples |
|---|---|
| Booleans | bool |
| Characters | char, wchar_t, char8_t, char16_t, char32_t |
| Strings | std::string, std::string_view, const char * |
| Wide strings | std::wstring, std::wstring_view, const wchar_t * |
| Numbers | int, double, std::size_t, etc. |
| Null | nullptr |
| Enums | enum, enum class |
| Filesystem | std::filesystem::path |
| Optional | std::optional<T> |
| Variant | std::variant<Ts...> |
| Any | std::any |
| Reference wrapper | std::reference_wrapper<T> |
| Chrono duration | std::chrono::seconds, milliseconds, etc. |
| Chrono time point | std::chrono::time_point |
| Smart pointers | std::unique_ptr, std::shared_ptr, std::weak_ptr |
| Raw pointers | T * |
| Function pointers | function pointer values |
| Ranges | std::vector, std::list, std::deque, etc. |
| Sets | std::set, std::unordered_set, etc. |
| Maps | std::map, std::unordered_map, etc. |
| Container adapters | std::stack, std::queue, std::priority_queue |
| Tuple-like values | std::tuple, std::pair, std::array |
| Error types | std::error_code, std::error_condition |
| Byte | std::byte |
| Monostate | std::monostate |
| Streamable types | Any type with operator<< |
| Custom inspected types | vix::inspector<T>, vix_inspect, or field_map<T> |
If C++23 std::expected is available, std::expected<T, E> is also supported.
Strings
inspect shows strings with quotes and length information when type display is enabled.
vix::inspect(std::string{"hello"});Output shape:
"hello" [len=5]Booleans
vix::inspect(true);
vix::inspect(false);Output:
true
falseCharacters
vix::inspect('A');Output:
'A'Unsigned character values may be shown as hexadecimal.
Null values
vix::inspect(nullptr);Output:
nullptrVectors and sequences
vix::inspect(std::vector<int>{1, 2, 3});Output shape:
[1, 2, 3] [n=3]Maps
std::map<std::string, int> values = {
{"users", 120},
{"orders", 42}
};
vix::inspect(values);Output shape:
{"orders": 42, "users": 120} [n=2]The exact ordering depends on the container.
Optionals
std::optional<int> a = 42;
std::optional<int> b;
vix::inspect(a);
vix::inspect(b);Output:
Some(42)
None<int>Variants
std::variant<int, std::string> value = std::string{"active"};
vix::inspect(value);Output shape:
variant<index=1>("active" [len=6])Any
std::any a = 42;
std::any empty;
vix::inspect(a);
vix::inspect(empty);Output shape:
any(int)
any(empty)std::any shows the stored type name, not the stored value.
Filesystem paths
std::filesystem::path path = "src/main.cpp";
vix::inspect(path);Output shape:
path("src/main.cpp") [exists=true]The exists value depends on the filesystem.
Chrono durations
using namespace std::chrono;
vix::inspect(42ns);
vix::inspect(100us);
vix::inspect(1500ms);
vix::inspect(60s);
vix::inspect(2min);
vix::inspect(1h);Output shape:
42ns
100µs
1500ms
60s
2min
1hChrono time points
auto now = std::chrono::system_clock::now();
vix::inspect(now);Output shape:
<time_point: 1710000000000ms from epoch>Smart pointers
auto value = std::make_unique<int>(42);
std::unique_ptr<int> empty;
vix::inspect(value);
vix::inspect(empty);Output:
unique_ptr(42)
unique_ptr(null)Shared pointers show the use count:
auto shared = std::make_shared<std::string>("hello");
vix::inspect(shared);Output shape:
shared_ptr[use_count=1]("hello" [len=5])Weak pointers show whether they are expired or lockable.
std::weak_ptr<std::string> weak = shared;
vix::inspect(weak);Output shape:
weak_ptr[use_count=2]("hello" [len=5])Raw pointers
int value = 42;
int *ptr = &value;
vix::inspect(ptr);Output shape:
<ptr:0x...>By default, raw pointers show their address.
To inspect the pointed-to value, enable show_address:
vix::inspect_options opts;
opts.show_address = true;
vix::inspect(ptr, opts);Output shape:
<ptr:0x...> -> 42Function pointers
void (*fn)(int) = [](int) {};
vix::inspect(fn);Output shape:
<fptr:0x...>Container adapters
Container adapters are copied before inspection, so the original container is not modified.
Stack
std::stack<int> s;
s.push(1);
s.push(2);
s.push(3);
vix::inspect(s);Output shape:
stack[1, 2, 3]Queue
std::queue<std::string> q;
q.push("first");
q.push("second");
vix::inspect(q);Output shape:
queue["first" [len=5], "second" [len=6]]Priority queue
std::priority_queue<int> pq;
pq.push(5);
pq.push(1);
pq.push(4);
vix::inspect(pq);Output shape:
priority_queue[5, 4, 1]Type metadata
inspect_type<T>() prints a detailed report about a type.
vix::inspect_type<int>();
vix::inspect_type<std::vector<int>>();Output shape:
type_info {
name: vector<int>
full_name: std::vector<int, std::allocator<int> >
size: 24 bytes
align: 8 bytes
categories: [class]
traits: [...]
}Inspect the type of a value
std::vector<int> values = {1, 2, 3};
vix::inspect_type(values);This deduces the type from the value.
Type metadata structure
Internally, Vix builds a type_metadata object.
It includes:
| Field group | Examples |
|---|---|
| Type names | name, full_name |
| Memory layout | size_bytes, align_bytes |
| Categories | is_integral, is_class, is_enum, is_pointer, etc. |
| Qualifiers | is_const, is_volatile |
| Class traits | is_aggregate, is_standard_layout, is_trivially_copyable, etc. |
| Construction traits | is_default_constructible, is_copy_constructible, etc. |
| Sign traits | is_signed, is_unsigned |
You can build metadata manually:
auto meta = vix::make_type_metadata<std::vector<int>>();Inspect value plus metadata
Use inspect_meta to show both the value and the type report.
std::vector<int> values = {1, 2, 3};
vix::inspect_meta(values);Output shape:
value: [1, 2, 3] [n=3]
type_info {
name: vector<int>
size: 24 bytes
align: 8 bytes
categories: [class]
traits: [...]
}Verbose inspection
inspect_verbose enables type tags, metadata mode, and address display.
int value = 42;
int *ptr = &value;
vix::inspect_verbose(ptr);Use it when normal inspection is not enough.
Inspect containers
inspect_container prints container-specific metadata.
std::vector<int> values = {1, 2, 3};
vix::inspect_container(values);Output shape:
vector<int> {
size: 3
capacity: 3
max_size: ...
empty: false
value_type: int
value_size: 4 bytes
elements: [1, 2, 3]
}For unordered containers, it can also show bucket information when available.
Inspect raw bytes
inspect_bytes prints a hexadecimal byte dump.
It only works for trivially copyable types.
int value = 42;
vix::inspect_bytes(value, "answer");Output shape:
answer - int [4 bytes @ 0x...]:
2A 00 00 00The byte order depends on the machine architecture.
Inspect two values
Use inspect_diff to compare two values side by side.
vix::inspect_diff(42, 43, "expected", "actual");Output:
expected: 42
actual: 43
types_equal: true
values_equal: falseIt prints values_equal only when operator== is available.
Inspect checks
inspect_check prints a PASS or FAIL result.
vix::inspect_check("2 + 2 == 4", 4, 2 + 2);
vix::inspect_check("1 + 1 == 3", 3, 1 + 1);Output shape:
[PASS] 2 + 2 == 4
[FAIL] 1 + 1 == 3
expected: 3
actual: 2It also returns a bool.
bool ok = vix::inspect_check("sum", 10, 5 + 5);Inspect tap
inspect_tap inspects a value and returns it unchanged.
int value = vix::inspect_tap(2 + 3, "sum");
vix::print(value);Output shape:
sum: 5
5Use this to inspect intermediate values without breaking expression flow.
Conditional inspect
int value = 42;
vix::inspect_if(value > 10, value, "value");This only prints when the condition is true.
Tap with custom function
auto value = vix::tap_with(42, [](const auto &x) {
vix::inspect_value("intermediate", x);
});tap_with calls the function, then returns the original value.
Inspect numeric ranges
inspect_numeric prints statistics for arithmetic ranges.
std::vector<int> scores = {10, 20, 30, 40, 50};
vix::inspect_numeric(scores, "scores");Output shape:
scores:
count: 5
min: 10
max: 50
sum: 150
mean: 30
stddev: 14.1421
histogram:
[...]For small or simple ranges, the histogram may not be printed.
Inspect a tree
inspect_tree prints nested structures as a visual tree.
std::map<std::string, std::vector<int>> data = {
{"a", {1, 2, 3}},
{"b", {4, 5, 6}}
};
vix::inspect_tree(data, "data");Output shape:
└─ data [2 items]
├─ a [3 items]
│ ├─ [0]: 1
│ ├─ [1]: 2
│ └─ [2]: 3
└─ b [3 items]
├─ [0]: 4
├─ [1]: 5
└─ [2]: 6Use inspect_tree for nested maps, vectors, optionals, variants, and structs registered with field_map.
Custom type support
There are three main ways to teach inspect about custom types.
- Define
operator<< - Define an ADL
vix_inspecthook - Specialize
vix::inspector<T> - Register fields with
vix::field_map<T>
field_map is the most structured option.
Method 1: use operator<<
#include <ostream>
#include <string>
#include <vix/inspect.hpp>
struct User
{
int id{};
std::string name;
};
std::ostream &operator<<(std::ostream &os, const User &user)
{
return os << "User{id=" << user.id << ", name=" << user.name << "}";
}
int main()
{
User user{1, "Ada"};
vix::inspect(user);
return 0;
}Use this when stream output is useful outside Vix too.
Method 2: use ADL vix_inspect
Define vix_inspect in the same namespace as the type.
#include <vix/inspect.hpp>
namespace app
{
struct Vec2
{
float x{};
float y{};
};
void vix_inspect(vix::inspect_context &ctx, const Vec2 &v)
{
ctx.os << "Vec2{x=" << v.x << ", y=" << v.y << "}";
}
}
int main()
{
app::Vec2 v{1.5f, 2.5f};
vix::inspect(v);
return 0;
}Use this when you want Vix-specific inspection without specializing templates.
Method 3: specialize vix::inspector<T>
#include <string>
#include <vix/inspect.hpp>
struct NamedResult
{
std::string label;
double value{};
};
template <>
struct vix::inspector<NamedResult>
{
static void inspect(vix::inspect_context &ctx, const NamedResult &result)
{
ctx.os << result.label << '=' << result.value;
if (ctx.opts.show_type)
ctx.os << " [NamedResult]";
}
};
int main()
{
vix::inspect(NamedResult{"loss", 0.42});
return 0;
}Use this when you want full control over inspection.
Method 4: register fields with field_map
field_map gives Vix a lightweight reflection-like way to inspect struct fields.
#include <string>
#include <vector>
#include <optional>
#include <vix/inspect.hpp>
struct OptimizerConfig
{
std::string name;
int batch_size{};
double learning_rate{};
bool use_cache{};
std::vector<int> layer_sizes;
std::optional<double> dropout;
};
template <>
struct vix::field_map<OptimizerConfig>
{
static constexpr auto fields()
{
return vix::fields(
vix::field("name", &OptimizerConfig::name),
vix::field("batch_size", &OptimizerConfig::batch_size),
vix::field("learning_rate", &OptimizerConfig::learning_rate),
vix::field("use_cache", &OptimizerConfig::use_cache),
vix::field("layer_sizes", &OptimizerConfig::layer_sizes),
vix::field("dropout", &OptimizerConfig::dropout)
);
}
};
int main()
{
OptimizerConfig cfg{
"adam",
64,
0.001,
true,
{128, 64, 32},
0.1
};
vix::inspect(cfg);
vix::inspect_report(cfg);
vix::inspect_tree(cfg, "config");
return 0;
}Output shape:
OptimizerConfig {
name: "adam" [len=4],
batch_size: 64,
learning_rate: 0.001,
use_cache: true,
layer_sizes: [128, 64, 32] [n=3],
dropout: Some(0.1)
}Field descriptors
field creates a field descriptor:
vix::field("name", &User::name)fields groups descriptors into a tuple:
return vix::fields(
vix::field("id", &User::id),
vix::field("name", &User::name)
);This is used by field_map<T>::fields().
Inspect reports for structs
inspect_report works for types that have a field_map.
vix::inspect_report(cfg);Output shape:
══ Inspect Report: OptimizerConfig ══
sizeof: ...
alignof: ...
layout: standard
trivial: no
fields:
name: "adam" [len=4]
batch_size: 64
learning_rate: 0.001
use_cache: true
layer_sizes: [128, 64, 32] [n=3]
dropout: Some(0.1)
══════════════════════════════Inspection priority
When Vix inspects a value, it chooses the first matching path.
Priority:
vix::inspector<T>specialization- ADL
vix_inspect field_map<T>nullptr_tbool- character types
- wide strings
- string-like types
std::filesystem::pathstd::anystd::optionalstd::variantstd::reference_wrapper- chrono duration
- chrono time point
std::unique_ptrstd::shared_ptrstd::weak_ptr- container adapters
std::expected, when available- enum
- map-like range
- sequence range
- pair
- tuple-like
- raw pointer
- streamable via
operator<< - fallback uninspectable type
Inspect the selected path
Use inspect_path<T>() to see which path will be used.
vix::print(vix::inspect_path<int>());
vix::print(vix::inspect_path<std::vector<int>>());
vix::print(vix::inspect_path<std::map<std::string, int>>());Output shape:
bool
range
map-like rangePrint many paths:
vix::inspect_paths<
int,
std::string,
std::vector<int>,
std::map<std::string, int>,
std::optional<int>
>();Demangled type names
The inspect API includes helpers under vix::demangle.
std::string full = vix::demangle::type_name<std::vector<int>>();
std::string short_name = vix::demangle::short_type_name<std::vector<int>>();Useful helpers:
| API | Purpose |
|---|---|
vix::demangle::type_name<T>() | Full human-readable type name when supported. |
vix::demangle::type_name_of(value) | Type name of a deduced value. |
vix::demangle::shorten(name) | Remove common namespace noise. |
vix::demangle::short_type_name<T>() | Shortened type name. |
On GCC and Clang, Vix uses ABI demangling when available. On other compilers, it falls back to typeid().name().
Complete example
#include <map>
#include <optional>
#include <string>
#include <variant>
#include <vector>
#include <vix/inspect.hpp>
#include <vix/print.hpp>
struct User
{
int id{};
std::string name;
std::vector<std::string> roles;
std::optional<double> score;
};
template <>
struct vix::field_map<User>
{
static constexpr auto fields()
{
return vix::fields(
vix::field("id", &User::id),
vix::field("name", &User::name),
vix::field("roles", &User::roles),
vix::field("score", &User::score)
);
}
};
int main()
{
User user{
1,
"Ada",
{"admin", "developer"},
98.5
};
vix::inspect(user);
vix::inspect_report(user);
vix::inspect_tree(user, "user");
vix::inspect_type<User>();
vix::inspect_meta(user);
std::vector<int> values = {10, 20, 30, 40, 50};
vix::inspect_container(values);
vix::inspect_numeric(values, "values");
vix::inspect_check("user id", 1, user.id);
std::string compact = vix::inspect_compact(user);
vix::print_named("compact", compact);
return 0;
}Use in a Vix app
#include <vix.hpp>
#include <vix/inspect.hpp>
using namespace vix;
int main()
{
App app;
app.get("/debug", [](Request &req, Response &res) {
vix::inspect_value("path", req.path());
vix::inspect_value("query", req.query());
res.json({
"ok", true,
"message", "debug inspected"
});
});
app.run(8080);
return 0;
}Use this during local development.
For production logs, prefer:
#include <vix/log.hpp>
vix::log::info("debug route called");Common mistakes
Forgetting the header
// Wrong
vix::inspect(value);Fix:
#include <vix/inspect.hpp>Printing instead of inspecting
Use print for simple output:
vix::print("hello", 42);Use inspect for debugging values:
vix::inspect(std::vector<int>{1, 2, 3});Inspecting huge containers
std::vector<int> values(1'000'000);
vix::inspect(values);Better:
vix::inspect_options opts;
opts.max_items = 20;
vix::inspect(values, opts);Recursing too deeply
For nested structures, set max_depth.
vix::inspect_options opts;
opts.max_depth = 3;
vix::inspect(data, opts);Expecting std::any to show the stored value
std::any value = 42;
vix::inspect(value);Output shape:
any(int)std::any shows the stored type name, not the stored value.
Expecting raw pointers to dereference by default
int value = 42;
int *ptr = &value;
vix::inspect(ptr);Output shape:
<ptr:0x...>Enable show_address if you want pointer dereference inspection when possible.
Using inspect_bytes on non-trivially-copyable types
inspect_bytes requires a trivially copyable type.
Good:
int x = 42;
vix::inspect_bytes(x);Not good:
std::string s = "hello";
// vix::inspect_bytes(s); // not intendedUsing inspect as production logging
This is useful during development:
vix::inspect(user);For production logs, use:
vix::log::info("user loaded");Best practices
Use inspect while developing:
vix::inspect(value);Use inspect_value for named values:
vix::inspect_value("config", config);Use inspect_type when learning or debugging template types:
vix::inspect_type<decltype(value)>();Use field_map for important structs:
template <>
struct vix::field_map<MyStruct>
{
static constexpr auto fields()
{
return vix::fields(
vix::field("id", &MyStruct::id),
vix::field("name", &MyStruct::name)
);
}
};Use inspect_report for structured objects.
Use inspect_tree for nested data.
Use inspect_numeric for numeric ranges.
Use inspect_check for lightweight debug checks.
API reference
inspect
template <typename T>
void inspect(const T &value);Inspects a value to the default output stream.
vix::inspect(42);inspect with options
template <typename T>
void inspect(const T &value, const inspect_options &opts);Inspects a value with explicit options.
vix::inspect_options opts;
opts.compact = true;
vix::inspect(value, opts);inspect_to
template <typename T>
void inspect_to(std::ostream &os, const T &value);Inspects a value to a specific stream.
std::ostringstream out;
vix::inspect_to(out, value);inspect_to_string
template <typename T>
std::string inspect_to_string(const T &value);
template <typename T>
std::string inspect_to_string(const T &value, const inspect_options &opts);Returns inspection output as a string.
std::string s = vix::inspect_to_string(value);inspect_type
template <typename T>
void inspect_type();
template <typename T>
void inspect_type(const T &value);Prints type metadata.
vix::inspect_type<std::vector<int>>();
std::vector<int> values;
vix::inspect_type(values);inspect_line
template <typename... Args>
void inspect_line(const Args &...args);Inspects multiple values on a single line separated by |.
vix::inspect_line(1, 2, 3);inspect_value
template <typename T>
void inspect_value(std::string_view label, const T &value);Inspects a named value.
vix::inspect_value("port", 8080);inspect_all
template <typename... Args>
void inspect_all(const Args &...args);Inspects several values, each on its own line.
vix::inspect_all("hello", 42, std::vector<int>{1, 2});inspect_meta
template <typename T>
void inspect_meta(const T &value);Prints the value and its full type metadata.
vix::inspect_meta(value);inspect_compact
template <typename T>
std::string inspect_compact(const T &value);Returns a compact inspection string.
std::string s = vix::inspect_compact(value);inspect_verbose
template <typename T>
void inspect_verbose(const T &value);Inspects with verbose settings.
vix::inspect_verbose(value);inspect_report
template <typename T>
void inspect_report(const T &obj);Requires field_map<T>.
Prints a detailed report for a struct.
vix::inspect_report(config);inspect_container
template <typename T>
void inspect_container(const T &c);Requires a range.
Prints container metadata and elements.
vix::inspect_container(std::vector<int>{1, 2, 3});inspect_bytes
template <typename T>
void inspect_bytes(const T &value, std::string_view label = "");Requires a trivially copyable type.
Prints a byte dump.
int value = 42;
vix::inspect_bytes(value, "value");inspect_diff
template <typename A, typename B>
void inspect_diff(
const A &a,
const B &b,
std::string_view label_a = "a",
std::string_view label_b = "b"
);Compares two values side by side.
vix::inspect_diff(42, 43, "expected", "actual");inspect_check
template <typename Expected, typename Actual>
bool inspect_check(
std::string_view label,
const Expected &expected,
const Actual &actual
);Prints PASS or FAIL and returns bool.
bool ok = vix::inspect_check("sum", 4, 2 + 2);inspect_tap
template <typename T>
const T &inspect_tap(const T &value, std::string_view label = "");Inspects and returns the original value.
auto result = vix::inspect_tap(compute(), "result");inspect_if
template <typename T>
void inspect_if(bool condition, const T &value, std::string_view label = "");Inspects only if the condition is true.
vix::inspect_if(debug_enabled, value, "value");tap_with
template <typename T, typename Fn>
const T &tap_with(const T &value, Fn &&fn);Runs a callback and returns the original value.
auto value = vix::tap_with(compute(), [](const auto &x) {
vix::inspect_value("x", x);
});inspect_numeric
template <typename Range>
void inspect_numeric(const Range &rng, std::string_view label = "");Requires a range of arithmetic values.
Prints numeric statistics.
vix::inspect_numeric(std::vector<int>{1, 2, 3}, "values");inspect_tree
template <typename T>
void inspect_tree(const T &value, std::string_view root_label = "root");Prints a tree representation.
vix::inspect_tree(data, "data");inspect_path
template <typename T>
std::string_view inspect_path() noexcept;Returns the selected inspection strategy for a type.
auto path = vix::inspect_path<std::vector<int>>();inspect_paths
template <typename... Ts>
void inspect_paths();Prints inspection strategies for several types.
vix::inspect_paths<int, std::string, std::vector<int>>();make_type_metadata
template <typename T>
type_metadata make_type_metadata();Builds type metadata for T.
auto meta = vix::make_type_metadata<MyType>();field
template <typename Owner, typename FieldT>
constexpr auto field(std::string_view name, FieldT Owner::*ptr);Creates a field descriptor.
vix::field("id", &User::id)fields
template <typename... Fields>
constexpr auto fields(Fields &&...fs);Groups field descriptors.
return vix::fields(
vix::field("id", &User::id),
vix::field("name", &User::name)
);field_map
template <typename T, typename = void>
struct field_map;Specialize this template to register fields for a custom struct.
template <>
struct vix::field_map<User>
{
static constexpr auto fields()
{
return vix::fields(
vix::field("id", &User::id),
vix::field("name", &User::name)
);
}
};inspector
template <typename T, typename = void>
struct inspector;Specialize this template to customize inspection.
template <>
struct vix::inspector<MyType>
{
static void inspect(vix::inspect_context &ctx, const MyType &value)
{
ctx.os << "...";
}
};streamable_inspector
template <typename T>
struct streamable_inspector;Helper for inspector specializations that delegate to operator<<.
template <>
struct vix::inspector<MyType> : vix::streamable_inspector<MyType>
{
};scoped_inspect_options
class scoped_inspect_options;Temporarily overrides default inspect options and restores them automatically.
{
vix::scoped_inspect_options guard{};
guard.opts.compact = true;
vix::inspect(value);
}Summary
vix::inspect is the debugging and diagnostics API for Vix.
Use it when you need to understand:
- values,
- types,
- containers,
- structs,
- nested data,
- memory bytes,
- numeric ranges,
- differences between values,
- selected rendering paths.
Core tools:
vix::inspect(value);
vix::inspect_value("name", value);
vix::inspect_type<T>();
vix::inspect_meta(value);
vix::inspect_report(obj);
vix::inspect_container(container);
vix::inspect_bytes(value);
vix::inspect_numeric(values);
vix::inspect_tree(data);
vix::inspect_check("label", expected, actual);For simple output, use vix::print.
For production logs, use vix::log.
For deep debugging, use vix::inspect.