Home > other >  Why does this std::enable_if only have the first parameter, and how does static_array match?
Why does this std::enable_if only have the first parameter, and how does static_array match?

Time:10-21

Here is a piece of code

// check if type of static array
template <class T>
struct ABIStaticArray : std::false_type  //#1
{
};

// stringN type => bytesN
template <std::size_t N>
struct ABIStaticArray<std::array<char, N>> : std::false_type  //#2
{
};

// a fixed-length array of N elements of type T.
template <class T, std::size_t N>
struct ABIStaticArray<std::array<T, N>> : std::true_type //#3
{
};

// fixed length of type, default 1 except static array type
template <class T, class Enable = void>
struct Length                                 //#4
{
    enum
    {
        value = 1
    };
};

// length of static array type
template <class T>
struct Length<T, typename std::enable_if<ABIStaticArray<T>::value>::type>     //#5
{
    enum
    {
        value = std::tuple_size<T>::value * Length<typename std::tuple_element<0, T>::type>::value
    };
};
  1. Why does the std::enable_if in specialized template of Length only have the first parameter?
  2. If I pass in a StaticArray, how does it match the specialized template of Length, if the value of first param of std::enable_if in specialized template of Length is true, the specialized template will become:
template <class T>
struct Length<T, void>
{
    enum
    {
        value = std::tuple_size<T>::value * Length<typename std::tuple_element<0, T>::type>::value
    };
};

why need this specialized template, what is the difference with the basic template of Length? the call of Length likes:

Length<std::array<int, 5>>::value

the result is 5

Please help, thanks very much!

CodePudding user response:

Let's see what is happening step by step. When you wrote:

Length<std::array<int, 5>>::value

Step 1) The template parameter T for Length is std::array<int, 5>

Step 2) Now there are two options that can be used. Either the primary template template <class T, class Enable = void> labeled as #4 or the specialization for static array #5. We want to find which one should be used. For this the condition typename std::enable_if<ABIStaticArray<std::array<int, 5>>::value>::type is tested.

Step 3) Now, ABIStaticArray<std::array<int, 5>> uses the 2nd specialization labeled as #3 because it is more specialized than the first specialization #2 and from the primary template #1.

Step 4) Since the second specialization is used, std::enable_if<ABIStaticArray<std::array<int, 5>>::value evaluates to true so that typename std::enable_if<ABIStaticArray<std::array<int, 5>>::value>::type evaluates to void. Basically, the specialization of Length is preferred over the primary template.

Step 5) Since the specialization of Length is selected the value is calculated using value = std::tuple_size<std::array<int, 5>>::value * Length<typename std::tuple_element<0, std::array<int, 5>>::type>::value which comes out to be 5.

To confirm this I modified your program slightly:

// length of static array type
template <class T>
struct Length<T, typename std::enable_if<ABIStaticArray<T>::value>::type>  //#5
{
    enum
    {
        value = std::tuple_size<T>::value * Length<typename std::tuple_element<0, T>::type>::value
    };
    Length()
    {
        std::cout <<"specialization #5"<<std::endl;
    }
};

int main()
{
    Length<std::array<int, 5>> v; //will use the specialization of Length
}

Working demo.

The output of the program is:

specialization #5
  • Related