C/C++ Arena

Step 4 of 9

Writing your own trait

The standard traits aren't magic. A trait is just a template struct with a value member, and specializations give different answers for different types. You can write your own in a few lines, exactly the way the standard library does.

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

template <typename T>
struct is_map : std::false_type {};                     // general case: no

template <typename K, typename V, typename C, typename A>
struct is_map<std::map<K, V, C, A>> : std::true_type {};   // any std::map: yes

template <typename T>
inline constexpr bool is_map_v = is_map<T>::value;

template <typename T>
std::string show(const T& x) {
    if constexpr (is_map_v<T>) {
        std::string out = "{";
        for (const auto& [k, v] : x) out += k + ":" + std::to_string(v) + " ";
        return out + "}";
    } else {
        return std::to_string(x);
    }
}

int main() {
    std::map<std::string, int> ages = {{"ann", 31}, {"bo", 4}};
    std::cout << show(ages) << "\n" << show(42) << "\n";
    std::cout << is_map_v<int> << is_map_v<std::map<int, int>> << "\n";
}
{ann:31 bo:4 }
42
01

How it works

Your task

std::vector has two template parameters, the element type and the allocator, so your specialization is over std::vector<T, A>. Then size_of uses if constexpr (is_vector_v<T>) to call x.size() only when x is a vector.

Your turn: write the is_vector trait and is_vector_v, then use it in size_of(const T& x): for a vector, return its size(); for anything else, return 1.

Previous: Type traits Next: Constraining templates with concepts