Type Traits

Back

Loading concept...

C++ Type Traits: Teaching Your Code to Know Itself 🧬

The Magic Mirror Analogy

Imagine you have a magic mirror that can tell you everything about any object you show it. “Is this a number? Is it red? Can it fly?” The mirror answers instantly!

In C++, Type Traits are like that magic mirror. They let your code ask questions about types at compile time—before your program even runs!


What Are Type Traits?

Type Traits are special tools that answer YES/NO questions about types.

Think of it like a guessing game:

  • “Is int a number?” → YES! âś…
  • “Is string a number?” → NO! ❌
  • “Is double a floating-point?” → YES! âś…

Your First Type Trait

#include <type_traits>
#include <iostream>

int main() {
    // Ask: "Is int an integer type?"
    if (std::is_integral<int>::value) {
        std::cout << "int is a number!";
    }
    return 0;
}

Output: int is a number!

The magic mirror (std::is_integral) looked at int and said “YES, it’s a whole number!”


Common Type Traits (Your Question Toolkit)

Here are questions you can ask:

Type Trait Question It Answers
is_integral<T> Is T a whole number?
is_floating_point<T> Is T a decimal number?
is_pointer<T> Is T a pointer?
is_array<T> Is T an array?
is_same<T, U> Are T and U the same type?

Example: Checking Multiple Types

#include <type_traits>
#include <iostream>

int main() {
    // Is double a decimal number?
    std::cout << std::is_floating_point<double>::value;
    // Output: 1 (true!)

    // Are int and int the same?
    std::cout << std::is_same<int, int>::value;
    // Output: 1 (true!)

    // Are int and double the same?
    std::cout << std::is_same<int, double>::value;
    // Output: 0 (false!)

    return 0;
}

static_assert: The Strict Teacher 📏

Imagine a teacher who checks your homework BEFORE you submit it. If something is wrong, you can’t even turn it in!

static_assert is that teacher. It checks conditions at compile time. If the check fails, your code won’t even compile!

The Story

You’re building a calculator. You want to make SURE nobody accidentally uses text instead of numbers.

#include <type_traits>

template<typename T>
T add(T a, T b) {
    // The strict teacher checks:
    // "Is T a number? If not, STOP!"
    static_assert(
        std::is_arithmetic<T>::value,
        "Only numbers allowed!"
    );
    return a + b;
}

int main() {
    add(5, 3);        // Works! âś…
    add(2.5, 1.5);    // Works! âś…
    // add("hi", "bye"); // ERROR! Won't compile ❌
    return 0;
}

How static_assert Works

static_assert(condition, "error message");
  • condition: Must be true at compile time
  • error message: Shown if condition is false

Real Example: Size Check

// Make sure int is 4 bytes on this system
static_assert(
    sizeof(int) == 4,
    "This code needs 4-byte integers!"
);

If int isn’t 4 bytes, the code refuses to compile. Safety first!


if constexpr: The Smart Switchboard 🔀

Regular if statements decide things when your program runs.

if constexpr decides things when your program compiles. It’s like choosing which road to build BEFORE the car even starts!

The Story

You run a printing shop. Some items need special treatment:

  • Numbers get formatted with commas
  • Text gets printed with quotes
  • Other things just get printed normally
#include <type_traits>
#include <iostream>
#include <string>

template<typename T>
void smartPrint(T value) {
    if constexpr (std::is_integral<T>::value) {
        // This code ONLY exists for integers
        std::cout << "Number: " << value << "\n";
    }
    else if constexpr (std::is_same<T, std::string>::value) {
        // This code ONLY exists for strings
        std::cout << "Text: \"" << value << "\"\n";
    }
    else {
        // Default for everything else
        std::cout << "Other: " << value << "\n";
    }
}

int main() {
    smartPrint(42);
    // Output: Number: 42

    smartPrint(std::string("Hello"));
    // Output: Text: "Hello"

    smartPrint(3.14);
    // Output: Other: 3.14

    return 0;
}

Why Not Regular if?

Regular if keeps ALL the code, even branches that will never run. This can cause errors!

template<typename T>
void broken(T value) {
    if (std::is_integral<T>::value) {
        // This line exists for ALL types
        int x = value + 1; // ERROR for strings!
    }
}

With if constexpr, the compiler removes branches that don’t apply. The code literally doesn’t exist for non-matching types!


The Power Trio: Working Together

Let’s combine all three tools in a real example!

Building a Safe Container

#include <type_traits>
#include <iostream>

template<typename T>
class SafeBox {
    // Rule 1: Only store copyable types
    static_assert(
        std::is_copy_constructible<T>::value,
        "SafeBox needs copyable types!"
    );

    T item;

public:
    SafeBox(T val) : item(val) {}

    void describe() {
        std::cout << "Box contains: ";

        if constexpr (std::is_arithmetic<T>::value) {
            std::cout << item << " (a number)\n";
        }
        else if constexpr (std::is_pointer<T>::value) {
            std::cout << "a pointer\n";
        }
        else {
            std::cout << "something\n";
        }
    }
};

int main() {
    SafeBox<int> numBox(42);
    numBox.describe();
    // Output: Box contains: 42 (a number)

    int x = 10;
    SafeBox<int*> ptrBox(&x);
    ptrBox.describe();
    // Output: Box contains: a pointer

    return 0;
}

Visual Flow: How Type Traits Work

graph TD A["Your Code Compiles"] --> B{Type Trait Check} B -->|is_integral?| C["Is it int, char, long?"] B -->|is_floating_point?| D["Is it float, double?"] B -->|is_same?| E["Compare two types"] C --> F["Returns true/false"] D --> F E --> F F --> G["static_assert uses result"] F --> H["if constexpr uses result"] G -->|true| I["Compile continues"] G -->|false| J["Compile ERROR!"] H -->|true| K["Branch code included"] H -->|false| L["Branch code removed"]

Quick Summary

Tool What It Does When It Runs
Type Traits Ask questions about types Compile time
static_assert Enforce rules with error messages Compile time
if constexpr Choose code paths based on types Compile time

Remember This! 🌟

  1. Type Traits = Magic mirror that answers questions about types
  2. static_assert = Strict teacher that stops bad code before it runs
  3. if constexpr = Smart switch that removes unused code paths

All three work at compile time—your program gets faster and safer because decisions are made BEFORE it runs!


Try It Yourself!

#include <type_traits>
#include <iostream>

template<typename T>
void mystery(T val) {
    static_assert(
        !std::is_pointer<T>::value,
        "No pointers allowed!"
    );

    if constexpr (std::is_integral<T>::value) {
        std::cout << "Got a whole number: " << val;
    } else {
        std::cout << "Got something else: " << val;
    }
}

int main() {
    mystery(100);    // What prints?
    mystery(3.14);   // What prints?
    // mystery(&val); // What happens?
    return 0;
}

Answers:

  • mystery(100) → “Got a whole number: 100”
  • mystery(3.14) → “Got something else: 3.14”
  • mystery(&val) → Won’t compile! “No pointers allowed!”

You now have the power to make your C++ code smarter, safer, and faster! 🚀

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.