Question
In standard C++, is it possible to print the type of a variable by name?
For example:
int a = 12;
std::cout << typeof(a) << std::endl;
Expected output:
int
What is the standard C++ way to do this, and are there any limitations?
Short Answer
By the end of this page, you will understand how C++ handles type information at compile time and runtime, why there is no standard typeof operator that directly prints int, and how tools like typeid, type traits, and compiler-specific name demangling are commonly used instead.
Concept
C++ does not provide a standard feature that guarantees you can write code like this:
std::cout << typeof(a);
and get a clean human-readable type name such as int.
The core idea is that types in C++ are mainly a compile-time concept. The compiler uses type information to check correctness, choose overloads, generate code, and optimize programs. But once the program runs, that exact source-level type name is not always preserved in a portable, readable form.
What standard C++ does provide
Standard C++ provides runtime type information through typeid:
#include <iostream>
#include <typeinfo>
int main() {
int a = 12;
std::cout << typeid(a).name() << '\n';
}
This gives you a type name string, but there is an important limitation:
typeid(...).name()is implementation-defined- That means the output depends on the compiler
- It may print
int, or it may print something cryptic like
Mental Model
Think of a C++ type like a label on a package while it is being sorted in a warehouse.
- During sorting, the label is extremely important
- Workers use it to send the package to the right place
- But after shipping, the warehouse system may not keep the original label in a neat, human-friendly form
In the same way, the C++ compiler depends heavily on type information while building your program. But at runtime, you are not guaranteed to get the exact source-code name back as a clean string.
So:
- compiler stage = types are rich and important
- runtime stage = some type info may exist, but readable names are limited
Syntax and Examples
Standard approach with typeid
#include <iostream>
#include <typeinfo>
int main() {
int a = 12;
std::cout << typeid(a).name() << '\n';
}
What this does
typeid(a)returns astd::type_infoobject describing the type.name()returns a C-style string representing that type- The exact string is compiler-dependent
Example with multiple types
#include <iostream>
#include <string>
#include <typeinfo>
int main() {
int a = 12;
b = ;
std::string c = ;
std::cout << (a).() << ;
std::cout << (b).() << ;
std::cout << (c).() << ;
}
Step by Step Execution
Consider this example:
#include <iostream>
#include <typeinfo>
int main() {
int a = 12;
std::cout << typeid(a).name() << '\n';
}
Step-by-step
1. int a = 12;
A variable named a is created with type int and value 12.
2. typeid(a)
The expression typeid(a) asks C++ for type information about a.
This produces a std::type_info object representing the type.
3. .name()
Calling .name() on that object returns a string-like C-style name for the type.
Real World Use Cases
Debugging template code
When working with templates, developers often want to inspect what type the compiler deduced:
template <typename T>
void printType(const T& value) {
std::cout << typeid(value).name() << '\n';
}
This can help during development, especially when generic code becomes hard to follow.
Logging unexpected values
In serialization, parsing, or generic utility code, you may log the type of a value when debugging behavior.
Verifying polymorphic behavior
With base-class references or pointers, typeid can help inspect the dynamic type when runtime type information is enabled and polymorphism is involved.
Unit testing generic utilities
Developers sometimes check that a helper produces the expected type using decltype and type traits instead of printing names.
static_assert(std::is_same_v<decltype(1 + 2), int>);
This is more reliable than printing type names.
Real Codebase Usage
In real C++ projects, developers usually do not rely on printing raw type names for core logic.
Common patterns
Guarding behavior with type traits
#include <type_traits>
template <typename T>
void process(const T& value) {
if constexpr (std::is_integral_v<T>) {
// handle integers
} else {
// handle other types
}
}
This is common in template-heavy code.
Using decltype for deduced types
auto x = 10;
decltype(x) y = 20;
Developers use this to keep types consistent without manually repeating them.
Debug-only type inspection
std::cerr << "Type: " << typeid(value).name() << '\n';
This is often used temporarily while debugging.
Common Mistakes
Mistake 1: Expecting typeof to be standard C++
int a = 12;
std::cout << typeof(a) << '\n';
This is not standard C++.
Fix
Use decltype for type deduction in code, or typeid for runtime inspection.
std::cout << typeid(a).name() << '\n';
Mistake 2: Assuming typeid(...).name() always prints int
int a = 12;
std::cout << typeid(a).name() << '\n';
You might expect:
int
But some compilers may print encoded names.
Fix
Treat .name() as useful for debugging, not as a portable user-facing string.
Comparisons
| Feature | Standard C++ | Purpose | Output readability | Best use |
|---|---|---|---|---|
typeid(expr).name() | Yes | Runtime type inspection | Implementation-defined | Debugging |
typeid(expr) == typeid(T) | Yes | Runtime type comparison | Not applicable | Checking types at runtime |
decltype(expr) | Yes | Get the type of an expression in code | Not printable directly | Declarations, templates |
std::is_same_v<T, U> | Yes | Compare types at compile time | Not printable directly |
Cheat Sheet
Quick reference
Print a type name candidate
#include <typeinfo>
std::cout << typeid(x).name() << '\n';
- Standard C++: yes
- Exact string output: not portable
Compare a variable's type
if (typeid(x) == typeid(int)) {
// x is int
}
Get a type in code
decltype(x) y = x;
decltype(x)is a type, not a string
Compile-time type check
#include <type_traits>
if constexpr (std::is_same_v<decltype(x), int>) {
// x is int
}
Rules to remember
FAQ
Can I print int exactly in standard C++?
Not portably. typeid(x).name() is standard, but the exact text it returns is implementation-defined.
Is typeof valid in C++?
Not in standard C++. Some compilers support it as an extension, but portable C++ should not rely on it.
What should I use instead of typeof in standard C++?
Use decltype to refer to a type in code, and typeid if you need runtime type information.
Why does typeid(a).name() print i instead of int?
Because the format of the returned name depends on the compiler implementation. Some compilers return mangled or abbreviated names.
How do I check whether a variable is an int?
Use typeid(a) == typeid(int) at runtime, or std::is_same_v<decltype(a), int> at compile time.
Is decltype(a) the same as typeid(a)?
No. gives you a type in code at compile time. gives type information at runtime.
Mini Project
Description
Build a small C++ program that inspects values of different types and shows how standard C++ can compare types safely, while also demonstrating the limits of printing human-readable type names. This helps reinforce the difference between runtime inspection and compile-time type checking.
Goal
Create a program that prints compiler-provided type names and reports whether each variable is an int using a safe standard approach.
Requirements
- Create variables of at least three different types
- Print each variable's type using
typeid(...).name() - Check whether each variable is an
int - Use standard C++ only
- Keep the output easy to read
Keep learning
Related questions
Advantages of Brace Initialization in C++
Learn why C++ brace initialization is often clearer and safer than other object initialization styles, with examples and common pitfalls.
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Aggregates, Trivial Types, Trivially Copyable Types, and PODs Explained
Learn what aggregates, trivial types, trivially copyable types, and PODs mean in C++, how they differ, and why they matter.