Serge Roussak
Serge Roussak

Reputation: 1807

Is there a way to specialize a function template by an array type?

Let's say, we need a function template which should return an integer depending on a type:

template<typename T>
int get_type();

Further, we do specialize it with couple of types:

template<>
int get_type<int>()
{
  return TYPE_INT;
}

// And so on for other types...

And this works well, but not for array types. I can do the following:

template<>
int get_type<char[]>()
{
  return TYPE_STRING;
}

and compiler "agrees" with this, but linker does not. Because the type char[] differs against, for example, the char[5].

Is there any way to implement this function template without function parameters? I.e., I know that we can do something like this:

template<typename T>
int get_type(const T&);

But, actually the function parameter is not needed (used) here.

EDIT:

I use the C++ 11.

Upvotes: 10

Views: 1028

Answers (4)

sparik
sparik

Reputation: 1201

Konrad already described the best approach in my opinion.

Here is another approach with overloads and specialization powered by SFINAE

// overload 1, for non-array types
template<typename T>
std::enable_if_t<!std::is_array_v<T>, int> get_type();

// specialization of overload 1 for int
template <>
auto get_type<int>() -> int {
    return 1;
}

// overload 2, for array types
template <typename T>
auto get_type() -> std::enable_if_t<std::is_array_v<T>, int> {
    return 3;
}

Upvotes: 3

Jarod42
Jarod42

Reputation: 217135

You cannot partial specialize template functions (but you can for template classes)

Another approach is tag dispatching with overloads, instead of specialization:

template <typename> struct Tag{};

constexpr int get_type(Tag<int>) { return TYPE_INT; }

template <std::size_t N>
constexpr int get_type(Tag<char[N]>) { return TYPE_STRING; }

template <typename T>
constexpr int get_type() { return get_type(Tag<T>{}); }

Upvotes: 10

Konrad Rudolph
Konrad Rudolph

Reputation: 545528

You need a partial specialisation to account for variable array lengths, and C++ does not allow partially specialised function templates. The canonical solution is to (partially) specialise a class template with a (static) member (function), and dispatch to that from within your unspecialised function template:

namespace detail {
    template <typename T>
    struct get_type;

    template <>
    struct get_type<int> {
        static constexpr int value = TYPE_INT;
    };

    template <>
    struct get_type<char> {
        static constexpr int value = TYPE_CHAR;
    };

    template <typename T, std::size_t N>
    struct get_type<T[N]> {
        static constexpr int value = get_type<T>::value | TYPE_ARRAY;
    };

    template <std::size_t N>
    struct get_type<char[N]> {
        static constexpr int value = TYPE_STRING;
    };
} // namespace detail

template<typename T>
constexpr int get_type() {
    return detail::get_type<T>::value;
}

Upvotes: 8

ForEveR
ForEveR

Reputation: 55887

You can't partially specialize function for array with size. But you can do it with class.

template<typename T>
class type
{
    static int get_type();
};

template<>
struct type<int>
{
    static int get_type() { return 1; }
};

template<size_t SZ>
struct type<char[SZ]>
{
    static int get_type() { return 2; }
};

template<typename T>
int get_type() { return type<T>::get_type(); }

int main()
{
    std::cout << get_type<char[3]>() << std::endl;
    return 0;
}

example

Upvotes: 6

Related Questions