Шаблонное метапрограммирование - разница между использованием 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.

Другие вопросы по тегам