Enum как вычисленные константы - PullRequest
0 голосов
/ 31 октября 2018

На самом деле эта «проблема» кажется чрезвычайно простой. Делая некоторые вычисленные смещения значков, я предложил следующий подход:

namespace Icons {

  struct IconSet {
    constexpr IconSet(size_t base_offset) noexcept
      : base_offset_(base_offset), icon(base_offset * 3), iconSmall(icon + 1), iconBig(icon + 2) {
    }
    size_t icon;
    size_t iconSmall;
    size_t iconBig;

    size_t base_offset_;

    constexpr size_t next() const {
      return base_offset_ + 1;
    }
  };


  static constexpr IconSet flower = IconSet(0);
  static constexpr IconSet tree = IconSet(flower.next());
  static constexpr IconSet forest = IconSet(tree.next());
  static constexpr IconSet mountain = IconSet(forest.next());

 }

Теперь можно написать Icons::tree.iconBig, например, чтобы получить вычисленное смещение этого значка. По сути, дизайнер может изменять значки, иногда добавляя и удаляя их, но всегда должен предоставлять весь набор (обычный, маленький и большой) по соглашению.

Как вы видите, проблема с этим подходом заключается в том, что мне пришлось сделать эту функцию next() и использовать ее многократно - нормальный enum не имел бы этого недостатка.

Я знаю о BOOST_PP и других трюках с макросами, но я надеялся на что-то без макросов - поскольку у меня есть ощущение, что это не нужно, и я бы тогда предпочел то, что у меня уже есть, с простой функцией next(). Другим решением, конечно, было бы просто обычное перечисление и функция вычисления, но это побеждает цель выкладывать их предварительно вычисленными.

Следовательно, я ищу простое и портативное решение, которое предоставит такую ​​функциональность, как перечисление. Это не должно быть время компиляции или constexpr, если, например, просто inline сделает это проще.

Ответы [ 2 ]

0 голосов
/ 31 октября 2018

Вот подход, который вы можете использовать, основанный на выражении сгиба по целочисленной последовательности времени компиляции для создания экземпляров значков по индексу. Структурная привязка позволяет получить индивидуально названные нестатические переменные, не являющиеся constexpr.

Анонимное пространство имен внутри Icons делает те определения видимыми только в этой единице перевода, которые вы можете или не можете хотеть.

Ссылка проводника компилятора , чтобы вы могли самостоятельно изучить параметры кода.

#include <cstddef>
#include <array>
#include <utility>

namespace Icons {

struct IconSet {
    constexpr IconSet(size_t base_offset) noexcept 
      : base_offset_(base_offset), icon(base_offset * 3), iconSmall(icon + 1), iconBig(icon + 2) {
    }
    size_t icon;
    size_t iconSmall;
    size_t iconBig;

    size_t base_offset_;
};

template <std::size_t... Ints>
constexpr auto make_icons_helper(std::index_sequence<Ints...>) -> std::array<IconSet, sizeof...(Ints)> 
{
    return {IconSet(Ints)...};
}

template <size_t N>
constexpr auto make_icons()
{
    return make_icons_helper(std::make_index_sequence<N>{});
}

namespace {
    auto [flower, tree, forest, mountain] = make_icons<4>();
}

}

int main()
{
    return Icons::forest.iconSmall;
}
0 голосов
/ 31 октября 2018

Простое решение non-constexpr, использующее статический счетчик и опирающееся на тот факт, что статическая инициализация выполняется сверху вниз в пределах одного TU:

namespace Icons {
  namespace detail_iconSet {
    static std::size_t current_base_offset = 0;
  }

  struct IconSet {
    IconSet() noexcept 
      : base_offset_(detail_iconSet::current_base_offset++)
      , icon(base_offset_ * 3)
      , iconSmall(icon + 1)
      , iconBig(icon + 2) { }

    std::size_t base_offset_;

    std::size_t icon;
    std::size_t iconSmall;
    std::size_t iconBig;
  };


  static IconSet flower;
  static IconSet tree;
  static IconSet forest;
  static IconSet mountain;
}

Смотрите его в прямом эфире на Coliru

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

...