Подчиненные константы C ++

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

Я пытаюсь найти способ объявить идентификаторы для моих подкатегорий, «подчиненные» идентификаторам для категорий, т.е. так, чтобы к идентификатору подкатегории можно было получить доступ через связанный идентификатор категории с разрешением во время компиляции.

Как правильно сделать это в C ++ 14?

Идентификаторы - это просто постоянные значения перечислимого типа (пусть основанные на int).

Вот что я пробовал:

enum Category
{
  One = 1,
  Two = 2,
  Three = 3
};

template<Category categoryName> struct Subcategory;

template<> struct Subcategory<Category::One>
{
  enum
  {
    A = 0,
    B = 1
  };
};

Мы можем получить доступ к идентификатору подкатегории через Subcategory<Category::One>::A (не волнение ...)

Выражение выглядит слишком длинным, и я пытаюсь найти решение, дающее несколько более сжатое выражение для доступа к A. Последнее средство на этом пути - сделать первое перечисление безымянным ...

На самом деле, как заметил Pepper_chico, выражение сокращено до Subcategory<One>::A. Есть ли решение (вероятно, не на основе шаблона), которое позволило бы избавиться от идентификатора Subcategory, оставив только One и A?


person user3900460    schedule 28.10.2014    source источник
comment
Пожалуйста, опубликуйте минимальный пример того, что вы пробовали и с какими проблемами столкнулись. Было бы намного проще помочь вам, если бы мы увидели, какую структуру имеют ваши классы (или что-то еще, что ваши категории отображают в C ++). Кроме того, что-то подсказывает мне, что вы имеете в виду что-то конкретное, когда говорите идентификатор. Вы имеете в виду имя типа, класса, перечисления, функции ...? Время выполнения, время компиляции?   -  person Oguk    schedule 28.10.2014
comment
Поскольку вы не используете enum class, вы можете без проблем превратить Subcategory<Category::One>::A в Subcategory<One>::A, разве этого не достаточно?   -  person pepper_chico    schedule 28.10.2014
comment
Я всегда просто использовал One_A, One_B. Есть причина, по которой вы этого не хотите?   -  person Mooing Duck    schedule 28.10.2014
comment
Pepper_chico - Да. Кажется, я просто не заметил этого. :)   -  person user3900460    schedule 28.10.2014
comment
Мучающая утка - Причина в том, что я просто хочу избежать дублирования One в идентификаторах подкатегорий (и имя идентификатора категории, конечно, может быть длиннее).   -  person user3900460    schedule 28.10.2014
comment
Я не знаю теории категорий, поэтому пытаюсь понять вашу проблему, даже не подозревая об этом. Могут быть другие подходы к той же проблеме лучше, чем ваш. Что касается вашего последнего запроса, вы можете сделать using SubOne = Subcategory<One>;, но вы просто создаете псевдоним.   -  person pepper_chico    schedule 28.10.2014
comment
С этим using, необходимым для каждой подкатегории, вы могли затем получить доступ к материалам с помощью SubOne::A, SubTwo::A и т. Д.   -  person pepper_chico    schedule 28.10.2014


Ответы (1)


Это немного странный прием, но, определяя объекты, соответствующие категориям, вы можете включить синтаксис One.A для имен подкатегорий (Живите в Coliru):

#include <iostream>
#include <type_traits>

enum class Category
{
  One = 1,
  Two = 2,
  Three = 3
};

template <Category> struct CategoryDescriptor;

#define DECLARE(name,...) \
template <> \
struct CategoryDescriptor<Category::name> { \
  enum sub_type { __VA_ARGS__ }; \
  constexpr operator Category() const { return Category::name; } \
}; \
constexpr CategoryDescriptor<Category::name> name{}

DECLARE(One, A, B);
DECLARE(Two, C, D);
DECLARE(Three, A, C, E);

#undef DECLARE

std::ostream& operator << (std::ostream& os, Category c) {
    return os << static_cast<std::underlying_type<Category>::type>(c);
}

template <Category C>
using SubCategoryOf = typename CategoryDescriptor<C>::sub_type;

int main() {
    std::cout << "One = " << One << "\n"
                 "One.A = " << One.A << "\n"
                 "Two = " << Two << "\n"
                 "Two.D = " << Two.D << "\n"
                 "Three = " << Three << "\n"
                 "Three.A = " << Three.A << '\n';

    // Category names convert to Category
    auto foo = [](Category){};
    foo(Three);

    // Subcategory names convert to SubCategoryOf<Category>
    auto bar = [](SubCategoryOf<Two>){};
    bar(Two.C);
}
person Casey    schedule 28.10.2014
comment
Ну ... Да решает проблему (по крайней мере формально). Извините, я пока не могу проголосовать из-за правил здесь, в SO ... - person user3900460; 29.10.2014