Шаблонное метапрограммирование - разница между использованием Enum Hack и Static Const
Мне интересно, в чем разница между использованием статического const и хаком enum при использовании методов метапрограммирования шаблонов.
EX: (Фибоначчи через TMP)
template< int n > struct TMPFib {
static const int val =
TMPFib< n-1 >::val + TMPFib< n-2 >::val;
};
template<> struct TMPFib< 1 > {
static const int val = 1;
};
template<> struct TMPFib< 0 > {
static const int val = 0;
};
против
template< int n > struct TMPFib {
enum {
val = TMPFib< n-1 >::val + TMPFib< n-2 >::val
};
};
template<> struct TMPFib< 1 > {
enum { val = 1 };
};
template<> struct TMPFib< 0 > {
enum { val = 0 };
};
Зачем использовать один над другим? Я читал, что взлом enum использовался до того, как статическая константа была поддержана внутри классов, но зачем использовать это сейчас?
3 ответа
Перечисления не являются lvals, значениями статических элементов являются, и, если они передаются по ссылке, шаблон будет создан:
void f(const int&);
f(TMPFib<1>::value);
Если вы хотите делать чистые вычисления времени компиляции и т. Д., Это нежелательный побочный эффект.
Основное историческое отличие состоит в том, что перечисления также работают для компиляторов, где инициализация значений элементов в классе не поддерживается, это должно быть исправлено в большинстве компиляторов сейчас.
Также могут быть различия в скорости компиляции между enum и static const.
В руководящих принципах буст-кодирования есть некоторые подробности и более старая ветка в буст-архивах по теме.
Для некоторых первое может показаться не таким взломанным и более естественным. Также у него есть выделенная память для себя, если вы используете класс, так что вы можете, например, взять адрес val.
Последний лучше поддерживается некоторыми старыми компиляторами.
С другой стороны, ответ Georg Fritzsche, когда структура, содержащая статическую переменную const, определена в специализированном шаблоне, она должна быть объявлена в источнике, чтобы компоновщик мог найти ее и фактически дать ему адрес, на который будет ссылаться, Это может излишне (в зависимости от желаемых эффектов) вызывать неэффективный код, особенно если вы пытаетесь создать библиотеку только с заголовками. Вы можете решить эту проблему, преобразовав значения в функции, которые возвращают значение, что также может открыть шаблоны для информации времени выполнения.
"enum hack" более ограничен и достаточно близок к #define
и это помогает инициализировать перечисление один раз, и принимать адрес enum
где-нибудь в программе, и обычно незаконно использовать адрес #define
, или. Если вы не хотите, чтобы люди получали указатель или ссылку на одну из ваших интегральных констант,enum
- хороший способ усилить это ограничение. Чтобы увидеть, как в TMP подразумевается, что во время рекурсии каждый экземпляр будет иметь свою собственную копиюenum { val = 1 }
во время рекурсии и каждый из них val
будет иметь надлежащее место в своем цикле. Как упомянул @Kornel Kisielewicz, "enum hack" также поддерживается более старыми компиляторами, которые запрещают указание начальных значений внутри класса темstatic const
.