Это идеально имитирует специализацию шаблона функции? - PullRequest
4 голосов
/ 11 апреля 2010

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

Но если включена полная оптимизация компилятора (предположим, Visual Studio 2010), оптимизируется ли оператор if-else в следующем коде? И если это так, не означает ли это, что для всех практических целей это специализация шаблона функции без каких-либо затрат производительности?

template<typename T>
struct Holder
{
    T   data;

    template<int Number>
    void saveReciprocalOf();
};

template<typename T>
template<int Number>
void Holder<T>::saveReciprocalOf()
{
    //Will this if-else-statement get completely optimized out
    if(Number == 0)     data = (T)0;
    else                data = (T)1 / Number;
}

//-----------------------------------
void main()
{
    Holder<float> holder;
    holder.saveReciprocalOf<2>();
    cout << holder.data << endl;
}

Ответы [ 3 ]

3 голосов
/ 11 апреля 2010

Скорее всего, это будет оптимизировано. Но если вы хотите быть уверенным , вы можете использовать время компиляции if с помощью шаблонов, например, Реализация MPL if_ в Boost.

Или вы можете использовать SFINAE ( Boost. enable_if).

1 голос
/ 11 апреля 2010

Обычно способ решить эту проблему - перегрузка

template<typename T>
struct Outer {
  template<int I>
  void inner() { 
    inner(int_<I>());
  }

private:
  template<int I>
  struct int_ { };

  void inner(int_<0>) {
    // for I == 0
  }

  template<int I>
  void inner(int_<I>) {
    // for others...
  }
};

Это очень хорошо имитирует явные специализации и даже работает в тех случаях, когда проверка типа для других путей сходит с ума (в отличие от решения if)

// ...
  template<int I>
  void inner(int_<I>) {
    int tmp[I];
  }
// ...

Это работает, потому что этот путь используется только если I != 0. Теперь в вашем случае, я в первую очередь удивляюсь, почему вы просто не передаете нормальный аргумент функции. Похоже, что не требуется природа времени компиляции I.

// works just fine too in your example
template<typename T>
void Holder<T>::saveReciprocalOf(int Number)
{
    // Will this if-else-statement get completely optimized out
    if(Number == 0)     data = (T)0;
    else                data = (T)1 / Number;
}

Это также имеет хорошие шансы на оптимизацию, если компилятор встроит вызов функции. Использование нетипичного параметра шаблона, когда в этом нет особой необходимости, ограничивает возможности этой функции не работать со значениями времени выполнения.

0 голосов
/ 11 апреля 2010

Спасибо. Поскольку я хочу быть уверен, что условное выражение оптимизировано (потому что оно должно вызываться очень часто внутри глубоких циклов, и я использую переключающий регистр вне циклов, чтобы выбрать правильный путь), я, вероятно, в итоге буду использовать enable_if_c как в следующем коде:

using boost::enable_if_c;

template<typename T>
struct Dummy
{    
    template<int N>
    typename enable_if_c<N==2,bool>::type             isPrimary() {return true;}

    template<int N>
    typename enable_if_c<N==3,bool>::type             isPrimary() {return true;}

    template<int N>
    typename enable_if_c<N==5,bool>::type             isPrimary() {return true;}

    template<int N>
    typename enable_if_c<N!=2&&N!=3&&N!=5,bool>::type isPrimary() {return false;}
};

Мне это кажется немного менее загроможденным, чем предложение Йоханнеса. Хотя последний (по умолчанию) случай может стать довольно уродливым.

...