c++templates

how do I write a Container<T> trait and use its partial specialization as function params


Let's say a class is a MyContainer<T> if it has

size_t size()
T& operator[](size_t index)
const T& operator[](size_t index)

and I want to write a template function that accept a specific version of MyContainer, for example any container that indexes int values and float values

float add(const MyContainer<int> &left, const MyContainer<float> &right);

and use it like

vector<int> a;
some_custom_vector<float> b;
float res = add(a, b);

How can I achieve that?

I cannot use auto because I want to specify inner type

// can not specify inner type
template<typename MyContainer>
float add(const MyContainer &left, const MyContainer &right);

// can not specify inner type either
auto add(const auto &left, const auto &right);

I also tried using template <template <class> class MyContainer>, but the compiler can't infer the inner template parameter.


Solution

  • You want a concept:

    #include <cstddef>
    #include <concepts>
    
    template <typename C, typename T>
    concept MyContainer = requires(C &c, const C &cc, std::size_t n)
    {
        { cc.size() } -> std::same_as<std::size_t>;
        { c[n] } -> std::same_as<T &>;
        { cc[n] } -> std::same_as<const T &>;
    };
    
    float add(const MyContainer<int> auto &left, const MyContainer<float> auto &right) {}
    

    Note that, rather than specifying the custom container requirements like this, it's better to rely on built-in concepts from <ranges>:

    template <typename C, typename T>
    concept MyContainer = std::ranges::random_access_range<C>
        && std::same_as<std::ranges::range_value_t<C>, T>;
    
    float add(MyContainer<int> auto &&left, MyContainer<float> auto &&right)