C++ Academy · Lesson

Writing Custom Traits

Build your own type traits.

Lesson 4 of 413 steps

Writing Custom Traits is a free C++ Academy lesson on CoddyKit. This is lesson 4 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the C++ Academy learning path, and your progress syncs across the web and the CoddyKit app. The C++ Academy course includes 4 lessons in total.

Building Your Own Traits

When the standard library lacks the question you need, you can write a custom trait. A trait is simply a template that exposes ::value or ::type.

Primary Template + Specialization

The standard pattern: a primary template defaulting to false, plus a specialization that matches the type of interest and sets true.

#include <iostream>
#include <type_traits>

template <typename T>
struct is_ptr : std::false_type {};

template <typename T>
struct is_ptr<T*> : std::true_type {};

int main() {
    std::cout << is_ptr<int>::value << "\n";
    std::cout << is_ptr<int*>::value << "\n";
    return 0;
}

Inheriting from integral_constant

By inheriting from std::true_type or std::false_type, your trait automatically gets a value member and behaves like standard traits.

A Container Detector

Detect whether a type looks like a container by checking for nested members. Here we specialize on the presence of a value_type typedef via a helper.

#include <iostream>
#include <vector>
#include <type_traits>

template <typename T, typename = void>
struct has_value_type : std::false_type {};

template <typename T>
struct has_value_type<T, std::void_t<typename T::value_type>> : std::true_type {};

int main() {
    std::cout << has_value_type<std::vector<int>>::value << "\n";
    std::cout << has_value_type<int>::value << "\n";
    return 0;
}

std::void_t Explained

std::void_t<...> maps any valid type list to void. If any type inside is ill-formed, the specialization is dropped via SFINAE, so the primary false_type wins.

Detecting a Member Function

You can detect whether a type has a callable size() by testing the expression in a void_t.

#include <iostream>
#include <string>
#include <type_traits>

template <typename T, typename = void>
struct has_size : std::false_type {};

template <typename T>
struct has_size<T, std::void_t<decltype(std::declval<T>().size())>> : std::true_type {};

int main() {
    std::cout << has_size<std::string>::value << "\n";
    std::cout << has_size<int>::value << "\n";
    return 0;
}

declval

std::declval<T>() produces a fake value of type T in unevaluated contexts, letting you write decltype expressions without constructing an object.

A Transform Trait

Custom traits can also produce types. This one strips a pointer layer.

#include <iostream>
#include <type_traits>

template <typename T>
struct remove_one_pointer { using type = T; };

template <typename T>
struct remove_one_pointer<T*> { using type = T; };

int main() {
    using R = remove_one_pointer<int*>::type;
    std::cout << std::is_same_v<R, int> << "\n";
    return 0;
}

Providing _v and _t Helpers

Match the standard style by adding variable and alias templates.

#include <iostream>
#include <type_traits>

template <typename T>
struct is_char : std::false_type {};
template <>
struct is_char<char> : std::true_type {};

template <typename T>
inline constexpr bool is_char_v = is_char<T>::value;

int main() {
    std::cout << is_char_v<char> << "\n";
    std::cout << is_char_v<int> << "\n";
    return 0;
}

Detection Idiom

The void_t technique generalizes into the detection idiom, which the experimental std::is_detected formalizes. C++20 concepts make much of this cleaner.

Testing Your Traits

Verify custom traits with static_assert so any regression breaks the build immediately.

#include <type_traits>

template <typename T>
struct is_void_like : std::false_type {};
template <>
struct is_void_like<void> : std::true_type {};

static_assert(is_void_like<void>::value);
static_assert(!is_void_like<int>::value);

int main() { return 0; }

Quick Check

Recall the role of std::void_t.

Recap

You learned to write custom traits.

  • Primary template defaults false; specialization sets true
  • Inherit from true_type/false_type
  • void_t + declval power the detection idiom
  • Add _v/_t helpers and test with static_assert
Free to start

Learn C++ with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
51
Lessons
203

Frequently Asked Questions

Is the “Writing Custom Traits” lesson free?

Yes — any 3 lessons of the C++ Academy learning path, including “Writing Custom Traits”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The C++ Academy course includes 4 lessons in total.

What will I learn in “Writing Custom Traits”?

Build your own type traits. You practise C++ Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start C++ Academy?

No prior experience is required. C++ Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 4 of 4.

How long does the “Writing Custom Traits” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this C++ Academy lesson?

Yes. Every C++ Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Querying Types
  2. Transforming Types
  3. Conditional Logic
  4. Writing Custom Traits
← Back to C++ Academy