Search code examples
templatesc++17overloading

How to implement multi dispatching with c++ function template


Here is what I want:

struct type1{};

template <typename T, std::enable_if_t<std::is_xxx_v<T, type1>,void>* = nullptr>
void my_function(const T& obj)
{
    std::cout << "operation on type1" << std::endl;
}

template <typename T, std::enable_if_t<!std::is_xxx_v<T, type1>,void>* = nullptr>
void my_function(const T& obj)
{
    std::cout << "operation on other types" << std::endl;
}

after days, i have to add another type struct type2{};

But how can I implement my_function for type1, type2 and other types? I can write it like this:

struct type2{};

template <typename T, std::enable_if_t<std::is_xxx_v<T, type1>,void>* = nullptr>
void my_function(const T& obj)
{
    std::cout << "operation on type1" << std::endl;
}

template <typename T, std::enable_if_t<std::is_xxx_v<T, type2>,void>* = nullptr>
void my_function(const T& obj)
{
    std::cout << "operation on type2" << std::endl;
}

// my_function for other types
template <typename T, std::enable_if_t<!std::is_xxx_v<T, type1> && !std::is_xxx_v<T, type2>,void>* = nullptr>
void my_function(const T& obj)
{
    std::cout << "operation on other types" << std::endl;
}

but this is not a good method, since one day, i add struct type3{};, i have to add a new func for type3 (i can accept this), but i also have to change code for other types which i don't want to.

what i want is if i add a new type3, is that possible that i only add a new overloaded function for type3, and the code for other types has no need to change.


Solution

  • Depending on the std::is_xxx_v you use, you might be able to use template specialization. First declare the default function working with any type of argument:

    template<typename T>
    void my_function_specialization(const T& obj) {
        std::cout << "operation on other types" << std::endl;
    }
    

    And then you can specialize the function on the types you want

    template<>
    void my_function_specialization(const type1& obj) {
        std::cout << "operation on type1" << std::endl;
    }
    
    template<>
    void my_function_specialization(const type2& obj) {
        std::cout << "operation on type2" << std::endl;
    }
    /*
     and so on...
    */
    

    Otherwise you can use if constexpr to distingush between different cases:

    template<typename T>
    void my_function_if_constexpr(const T& obj) {
        if constexpr (std::is_xxx_v<type1, T>) {
            std::cout << "operation on type1" << std::endl;
        } else if constexpr (std::is_xxx_v<type2, T>) {
            std::cout << "operation on type2" << std::endl;
        } else if constexpr (/* and so on... */) {
            /* ... */
        } else {
            std::cout << "operation on other types" << std::endl;
        }
    }
    

    See Demo