2013-05-12 2 views
3

Я пытаюсь написать частично специализированную функцию шаблона в теле шаблона class/struct. Частичная специализация выполняется для выполнения рекурсивного метапрограммирования шаблонов.Шаблон метапрограммирования внутри тела класса шаблона

template<size_t N> 
struct my_class { 

template<size_t D> double my_func(...){} 

template<> double my_func<0>(...){} 

double other_func(...){ return my_func<N-1>(...); } 
}; 

но г ++ (с использованием -std = C++ 0x варианта ) жалуется говоря, не может частично специализировать шаблон функции в классе/структуру и заставляет меня написать шаблон функции my_func вне область видимости класса в отдельном пространстве имен, как если бы они были статическими, в конечном счете передавая все переменные класса и делая код очень беспорядочным (все переменные-члены, на которые было бы легко ссылаться это).

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

Это делает код чище и намного проще в обслуживании. Я использую Ubuntu 12.04 и gcc 4.6.

Приветствие

ответ

4

Вы можете достичь желаемого результата путем перегрузки функции (не специализируя его), а затем с помощью enable_if, чтобы выборочно включить только одну или другие из перегрузок:

template<size_t D> typename std::enable_if<D!=0, double>::type my_func(...){} 

template<size_t D> typename std::enable_if<D==0, double>::type my_func(...){} 

enable_if ограничения означает, что когда D!=0 только первая перегрузка является жизнеспособной функцией, а когда D==0 только вторая перегрузка является жизнеспособной функцией.

В C++ 03 вы можете сделать то же самое с boost::enable_if_c.

Мой предпочтительным решением было бы заменить уродливую enable_if использование с типом пользовательского признака, может быть что-то вроде этого:

template<size_t> struct if_zero { typedef double disable; }; 
template<> struct if_zero<0> { typedef double enable; }; 

template<size_t D> typename if_zero<D>::disable my_func(...){} 
template<size_t D> typename if_zero<D>::enable my_func(...){} 

Это имеет тот же эффект, но в более literate programming стиле.

Другая форма, даже легче читать будет:

template<bool, typename T> struct If_ { typedef T enable; }; 
template<typename T> struct If_<false, T> { }; 

template<bool B, typename T> using If = typename If_<B, T>::enable; 

template<size_t D> If<D!=0, double> my_func(...){} 
template<size_t D> If<D==0, double> my_func(...){} 

Я думаю, что "Concepts Lite" предложение позволит это в гораздо более чистой образом ограничивая вторую перегрузку, как так:

template<size_t D> double my_func(...){} 

template<size_t D> requires (D == 0) 
    double my_func(...){} 

Здесь вторая перегрузка может быть вызвана только при D==0 и будет выбрана с помощью разрешения перегрузки, поскольку она более ограничена, чем первая перегрузка.

+0

SFINAE для победы, а? :-) Я искренне надеялся, что новый стандарт поддерживает частично заданный метапрограммирование шаблонов из коробки, без этих уродливых синтаксических трюков ... – Emanuele

+0

См. Версию шаблона 'If' alias, которую я добавил, что я думаю о лучшем синтаксисе, который вы может попасть в C++ 11. Если концепции превращаются в C++ 17, вы сможете использовать ограничения. –

Смежные вопросы