PatrykB
PatrykB

Reputation: 1709

Select appropriate function from enum

Let's say I have small library that I want to wrap in order to improve usability. I only want to wrapper them; I don't want to touch the existing code.

For example:

template <typename T>
class vector_type_A {
    //...
};
template <typename T>
class vector_type_B {
    //...
};
template <typename T>
class vector_type_C {
    //...
};

I can do this to wrap a class:

enum type_e {
    Type_A, Type_B, Type_C
};

template <type_e type, typename T>
class vector_selector;

template <typename T>
class vector_selector <Type_A, T> {
public: 
    using vector = vector_type_A<T>;
};
template <typename T>
class vector_selector <Type_B, T> {
public: 
    using vector = vector_type_B<T>;
};
template <typename T>
class vector_selector <Type_C, T> {
public: 
    using vector = vector_type_C<T>;
};

template <type_e type, typename T>
using vector = typename vector_selector<type,T>::vector;

But this doesn't wrap functions, only classes.

How can I write similar selector for functions?

Upvotes: 0

Views: 109

Answers (1)

Justin
Justin

Reputation: 25387

This would be easy if we could partially specialize function templates, but we can't, so we need to use a class to do this.

Given your functions (as an example):

template<typename T>
int fn_type_A(vector_type_A<T> const&) {
    return 0;
}

template<typename T>
int fn_type_B(vector_type_B<T> const&) {
    return 1;
}

template<typename T>
int fn_type_C(vector_type_C<T> const&) {
    return 2;
}

You can write this:

template<type_e type>
struct fn_selector;

template<>
struct fn_selector<Type_A>
{
    template<typename T>
    static int fn(vector_type_A<T> const& vec) {
        return fn_type_A(vec);
    }
};

template<>
struct fn_selector<Type_B>
{
    template<typename T>
    static int fn(vector_type_B<T> const& vec) {
        return fn_type_B(vec);
    }
};

template<>
struct fn_selector<Type_C>
{
    template<typename T>
    static int fn(vector_type_C<T> const& vec) {
        return fn_type_C(vec);
    }
};

template<type_e type, typename T>
int fn(vector<type, T> const& vec) {
    return fn_selector<type>::fn(vec);
}

If you find that you are writing many of these, you should probably combine them into a single selector:

template<type_e>
struct vector_selector;

template<>
struct vector_selector<Type_A>
{
    template<typename T>
    using type = vector_type_A<T>;

    template<typename T>
    static int fn(vector_type_A<T> const& vec) {
        return fn_type_A(vec);
    }
};

template<>
struct vector_selector<Type_B>
{
    template<typename T>
    using type = vector_type_B<T>;

    template<typename T>
    static int fn(vector_type_B<T> const& vec) {
        return fn_type_B(vec);
    }
};

template<>
struct vector_selector<Type_C>
{
    template<typename T>
    using type = vector_type_C<T>;

    template<typename T>
    static int fn(vector_type_C<T> const& vec) {
        return fn_type_C(vec);
    }
};

template <type_e type, typename T>
using vector = typename vector_selector<type>::template type<T>;

template<type_e type, typename T>
int fn(vector<type, T> const& vec) {
    return vector_selector<type>::fn(vec);
}

With C++17, you could simplify the function selection to:

template<type_e type, typename T>
int fn(vector<type, T> const& vec) {
    if constexpr (type == Type_A) {
        return fn_type_A(vec);
    } else if (type == Type_B) {
        return fn_type_B(vec);
    } else {
        static_assert(type == Type_C, "Unknown type");
        return fn_type_C(vec);
    }
}

Upvotes: 1

Related Questions