Специализация на C++ шаблон за конкретни стойности

Имам структура Opers с някои аритметични операции: mult(), div(), mod().

И трябва да специализирам шаблон за определени стойности на n. Ето пример за Opers<1>.

Но също така искам да направя специализация за n, които са степени на 2 (n = 2,4,8,16, ...) – в този случай мога да оптимизирам операции mult() и div() (използвайки побитово изместване наляво или надясно).

#include <iostream>
using namespace std;
template<int n> struct Opers {
    int mult(int x){
        return n*x;
    }
    int div(int x){
        return x / n;
    }   
    int mod(int x){
        return x % n;
    }   
};
template<> struct Opers<1> {
    int mult(int x){
        return 1;
    }
    int div(int x){
        return x;
    }   
    int mod(int x){
        return 0;
    }           
};
int main() {
    Opers<1> el2;
    cout << el2.mult(3) <<endl;
} 

Търся строителство като

template<> struct Opers<isPowerOfTwo()>
    int mult(int x){
        // do smth
     }

Възможно ли е или какво ръководство трябва да прочета?

UPD. Използването на C++11 е разрешено и дори би било по-добре.


person takka    schedule 02.06.2013    source източник
comment
Ааа... оптимизирайте с помощта на смени. Компилаторът ще бъде като, уау, никога не бих се сетил за това...   -  person Kerrek SB    schedule 02.06.2013
comment
Знам, че няма значение за компилатора! Това е само пример (свързан с учебната ми задача) и не мога да намеря правилна конструкция или подход към кода, който...   -  person takka    schedule 02.06.2013


Отговори (1)


В C++11 можете да го направите по този начин. Първо, променете основния си шаблон, така че да приема втори, фиктивен параметър:

template<int n, typename = void>
struct Opers 
{
    // ...
};

След това напишете функция constexpr, която определя дали цяло число е степен на 2:

constexpr bool is_power_of_two(int x)
{
    return (x == 1) || ((x % 2 == 0) && is_power_of_two(x / 2));
}

И накрая, използвайте SFINAE, за да активирате или деактивирате специализацията въз основа на резултата от вашата функция constexpr:

#include <type_traits>

template<int n>
struct Opers<n, typename std::enable_if<is_power_of_two(n)>::type>
{
    // ...
};
person Andy Prowl    schedule 02.06.2013
comment
Няма ли x & (x - 1) == 0 да провери същото? - person awesoon; 02.06.2013
comment
@soon: Може би, да, но намирам моята версия за по-лесна за разбиране. Освен това, това се прави по време на компилиране, така че е малко вероятно производителността да е проблем - person Andy Prowl; 02.06.2013
comment
Какво ще кажете за template<int n, bool ispow2 = is_power_of_two(n)>? - person dyp; 02.06.2013
comment
@DyP: Това също е възможност, но мисля, че моето решение е по-общо, защото позволява добавяне на нови специализации без промяна на основния шаблон - person Andy Prowl; 02.06.2013
comment
Благодаря много! Точно това търсех! - person takka; 02.06.2013