Search code examples
c++templatescode-generation

Difference between code generated using a template function and a normal function


I have a vector containing large number of elements. Now I want to write a small function which counts the number of even or odd elements in the vector. Since performance is a major concern I don't want to put an if statement inside the loop. So I wrote two small functions like:

long long countOdd(const std::vector<int>& v)
{
    long long count = 0;
    const int size = v.size();
    for(int i = 0; i < size; ++i)
    {
        if(v[i] & 1)
        {
            ++count;
        }
    }
    return count;
}

long long countEven(const std::vector<int>& v)
{
    long long count = 0;
    const int size = v.size();
    for(int i = 0; i < size; ++i)
    {
         if(0 == (v[i] & 1))
        {
            ++count;
        }
    }
    return count;
}

My question is can I get the same result by writing a single template function like this:

template <bool countEven>
long long countTemplate(const std::vector<int>& v1)
{
    long long count = 0;
    const int size = v1.size();
    for(int i = 0; i < size; ++i)
    {
        if(countEven)
        {
            if(v1[i] & 1)
            {
                ++count;
            }
        }
        else if(0 == (v1[i] & 1))
        {
            ++count;
        }
    }
    return count;
}

And using it like this:

int main()
{
  if(somecondition)
  {
     countTemplate<true>(vec); //Count even
  }      
  else
  {
     countTemplate<false>(vec); //Count odd
  } 
}

Will the code generated for the template and non-template version be the same ? or will there be some additional instructions emitted?

Note that the counting of numbers is just for illustration hence please don't suggest other methods for counting.

EDIT: Ok. I agree that it may not make much sense from performance point of view. But atleast from maintainability point of view I would like to have only one function to maintain instead of two.


Solution

  • Your template version will generate code like this:

    template <>
    long long countTemplate<true>(const std::vector<int>& v1)
    {
        long long count = 0;
        const int size = v1.size();
        for(int i = 0; i < size; ++i)
        {
            if(true)
            {
                    if(v1[i] & 1)
                    {
                            ++count;
                    }
            }
            else if(0 == (v1[i] & 1))
            {
                    ++count;
            }
        }
        return count;
    }
    
    
    template <>
    long long countTemplate<false>(const std::vector<int>& v1)
    {
        long long count = 0;
        const int size = v1.size();
        for(int i = 0; i < size; ++i)
        {
            if(false)
            {
                    if(v1[i] & 1)
                    {
                            ++count;
                    }
            }
            else if(0 == (v1[i] & 1))
            {
                    ++count;
            }
        }
        return count;
    }
    

    So if all optimizations are disabled, the if will in theory still be there. But even a very naive compiler will determine that you're testing a constant, and simply remove the if.

    So in practice, no, there should be no difference in the generated code. So you can use the template version and don't worry about this.