Могу ли я получить имя / ссылку на значение специализации внутри специализации шаблона?

#c #c 11 #templates #template-meta-programming

#c #c 11 #шаблоны #шаблон-мета-программирование

Вопрос:

Мой код:

 enum class list{one, two};
template <list T> class Base;
template <> class Base <list::one>{
    A a{list::one};
    B b{list::one};
    C c{list::one};
};
template <> class Base <list::two>{
    B b{list::two};
    C c{list::two};
    D d{list::two};
};
 

Но я хотел бы избежать дублирования кода и использовать ссылку на значение специализации, например:

 template <> class Base <list::one>{
    A a{T};
    B b{T};
    C c{T};
};
template <> class Base <list::two>{
    B b{T};
    C c{T};
    D d{T};
};
 

Я могу сделать временную переменную sludge, но она тоже выглядит не очень хорошо:

 template <> class Base <list::one>{
    list T = list::one;
    A a{T};
    B b{T};
    C c{T};
};
 

Есть ли какой-либо способ получить ссылку на значение специализации шаблона?

Комментарии:

1. Боюсь, что создание переменной — единственный вариант. Просто убедитесь, что вы добавили static constexpr к нему, чтобы он вел себя так же, как параметр шаблона.

Ответ №1:

В следующем примере я использую SFINAE для обеспечения T доступности в определении Base . В частности, я сделал следующее:

  • добавлен один параметр фиктивного типа в основной шаблон,
  • сделал две специализации частичными, не указав параметр T (и указав второй параметр фиктивного типа),
  • указан второй параметр фиктивного типа, который T равен list::one и list::two в двух специализациях, через std::enable_if_t .
 #include <iostream>
#include <type_traits>

enum class list{one, two};

// to make the code compile
class A { public: A(list) {} };
class B { public: B(list) {} };
class C { public: C(list) {} };
class D { public: D(list) {} };

// primary template (second param's sole purpose is to allow partial spec.)
template <list T, typename = void>
class Base;

// partial specialization #1
template <list T>
class Base <T, std::enable_if_t<T == list::one>>{
    A a{T};
    B b{T};
    C c{T};
  public:
    Base() { std::cout << "list::onen"; }
};

// partial specialization #2
template <list T>
class Base <T, std::enable_if_t<T == list::two>>{
    B b{T};
    C c{T};
    D d{T};
  public:
    Base() { std::cout << "list::twon"; }
};

int main() {
    Base<list::one> o;
    Base<list::two> t;
}
 

Это довольно стандартный способ использования SFINAE via std::enable_if . Похожие примеры можно найти на странице cppreference on std::enable_if , где последний пример (тот, что с первым комментарием // primary template ) повторяет приведенный выше код.