Является ли рекурсия шаблона более эффективной, чем рекурсия без шаблона?

Т.е. какой из двух лучше:

typedef std::vector<int> Ivec;
template <int N>
void test1(Ivec& v){
    assert(v.size() >= N);
    for (int i=0;i<N;i++){v[i]++;}
    test1<N-1>(v);
}
template <>
void test1<0>(Ivec& v){}


void test2(Ivec& v,int N){
    assert(v.size() >= N);
    for (int i=0;i<N;i++){v[i]++;}
    if (N == 1) {return;}
    test2(v,N-1);
}
0
463035818_is_not_a_number 25 Окт 2015 в 03:58

2 ответа

Лучший ответ

Я буду удивлен, если версия шаблона станет медленнее. В большинстве случаев это должно быть быстрее, если не каждый раз. В конце концов, версия шаблона вычисляет значения во время компиляции.

Вот программа, которая умножает два подхода.

#include <iostream>
#include <cstddef>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cassert>

typedef std::vector<int> Ivec;

template <int N>
void test1(Ivec& v){
   assert(v.size() >= N);
   for (int i=0;i<N;i++){v[i]++;}
   test1<N-1>(v);
}

template <>
void test1<0>(Ivec& v){}

void test2(Ivec& v,int N){
   assert(v.size() >= N);
   for (int i=0;i<N;i++){v[i]++;}
   if (N == 1) {return;}
   test2(v,N-1);
}

void timeFunction(void (*fun)())
{
   clock_t start = std::clock();
   fun();
   clock_t end = std::clock();
   double secs = 1.0*(end-start)/CLOCKS_PER_SEC;
   std::cout << "Time taken: " << secs << std::endl;
}

void time_test1()
{
   Ivec a;
   const int N = 500;
   for (int i = 0; i < N; ++i )
   {
      a.push_back(std::rand());
   }

   for ( int i = 0; i < N*20; ++i )
   {
      test1<N>(a);
   }
}

void time_test2()
{
   Ivec a;
   const int N = 500;
   for (int i = 0; i < N; ++i )
   {
      a.push_back(std::rand());
   }

   for ( int i = 0; i < N*20; ++i )
   {
      test2(a, N);
   }
}


int main()
{
   std::srand(time(NULL));
   timeFunction(time_test1);
   timeFunction(time_test2);
   return 0;
}

Программа построена на машине Linux с g ++ версии 4.8.4 с помощью команды:

g++ -Wall -std=c++11     socc.cc   -o socc

Выход:

Time taken: 3.96467
Time taken: 4.32788

Вывод подтверждает мою догадку. Как обычно, ваш пробег может отличаться.

1
R Sahu 25 Окт 2015 в 03:51

Рекурсия шаблона должна быть быстрее, но вам нужно знать N во время компиляции.

Что лучше?

Обычно рекурсия функций, поскольку она более гибкая и генерирует машинный код только один раз.

Но если вы знаете N во время компиляции (например, как определение), а не как что-то, что вы читаете из файла, а потребность в производительности больше, чем размер сгенерированного кода, то вы можете воспользоваться преимуществами оптимизации, которую компилятор сможет сделать.

0
Dragos Pop 25 Окт 2015 в 01:16