Klaus
Klaus

Reputation: 25663

template specialisation with arrays, std::is_array

I play around with template specialization and SFINAE.

As for the following example, the things seems easy:

    template <class T>
    void Do(T t, typename std::enable_if<std::is_integral<T>::value >::type* = 0)
    {
        cout << "is integer" << endl;
    }

    template <class T>
    void Do(T t, typename std::enable_if<std::is_floating_point<T>::value >::type* = 0)
    {
        cout << "is float" << endl;
    }

No I tried std::is_array, but the specialization with std::is_array is never used.

So I tried out why is_array never matches:

    template <int num>
    void Do( int a[num])
    {
        cout << "int array size " << num << endl;
    }

    void Do( int* x)
    {
        cout << "int*" << endl;
    }

    ...
    int e[] = { 1,2,3 };
    Do(e);
    ...

The first mystery for me is, that the specialization with "int a[num]" did never catch! The function parameter always has the type int*.

If I use reference types I got the "correct" result:

    template <int num>
    void Do( int (&a)[num])
    {
        cout << "int array size " << num << endl;
    }

    void Do( int* &x)
    {
        cout << "int*" << endl;
    }

So my question comes up: Is there a reasonable usage of std::is_array in combination with template function parameters? I know that

    cout << boolalpha << std::is_array<decltype(e)>::value << endl;

will give me the correct result. But declaring the template selection manually gives me no functional add on. I there any way to detect (with or without SFINAE) that an template specialization from function parameters fits to an array?

Upvotes: 2

Views: 2825

Answers (1)

jpalecek
jpalecek

Reputation: 47770

I think you got it yourself - pass arrays to template functions by reference, if you want to use their type in the secialization.

The reason you want to do this is array-to-pointer decay, which is one of the few implicit conversions that happen to template function arguments before they are matched to the parameter types. That's why T was a pointer when you tried to check that it is an array type in DoIt. However, array-to-pointer decay does not happen when the target type is reference type. So, to sum up:

template <class T>
void Do(T& t, typename std::enable_if<std::is_array<T>::value >::type* = 0)

should work.

BTW the boring way of not using SFINAE

template <class T, unsigned N>
void Do(T (&t)[N])

works too.

Upvotes: 5

Related Questions