Хотите, чтобы тип переключателя constexpr был на типе

В настоящее время я делаю этот трюк, чтобы иметь cstring на основе типа:

template<class ListT> static char constexpr * GetNameOfList(void)
{
  return
  std::conditional<
    std::is_same<ListT, LicencesList>::value, "licences",
    std::conditional<
      std::is_same<ListT, BundlesList>::value, "bundles",
      std::conditional<
        std::is_same<ListT, ProductsList>::value, "products",
        std::conditional<
          std::is_same<ListT, UsersList>::value, "users",
          nullptr
        >
      >
    >
  >;
}

Но этот код не очень красивый, и если мы хотим проверить больше типов, это может быть нечитаемым. Это способ сделать то же самое, что если бы был блок блокировки коммутатора?

На самом деле код сложнее, потому что std:: условный нужен какой-то тип, поэтому нам нужен какой-то класс, чтобы сделать трюк:

struct LicenceName { static char constexpr * value = "licences"; };

например.

Ответы

Ответ 1

Я думаю, что было бы проще использовать специализированную специализацию


пример кода

#include <iostream>
struct A{};
struct B{};
struct C{};
struct D{};

template<typename T> constexpr const char* GetNameOfList();
//here you may want to make it return nullptr by default

template<>constexpr const char* GetNameOfList<A>(){return "A";}
template<>constexpr const char* GetNameOfList<B>(){return "B";}
template<>constexpr const char* GetNameOfList<C>(){return "C";}

int main(){
   std::cout << GetNameOfList<A>() << '\n';
   std::cout << GetNameOfList<B>() << '\n';
   std::cout << GetNameOfList<C>() << '\n';
   //std::cout << GetNameOfList<D>() << '\n'; //compile error here
}

Ответ 2

Вам не нужно прибегать к метапрограммированию, просто if работает просто:

template<class ListT>
constexpr char const *GetNameOfList() {

    if(std::is_same<ListT, A>::value) return "A";
    if(std::is_same<ListT, B>::value) return "B";
    if(std::is_same<ListT, C>::value) return "C";
    if(std::is_same<ListT, D>::value) return "D";

    return nullptr;
}

Посмотрите на живое на Coliru

Ответ 3

Вы можете создать массив constexpr строк и кортежей типов списка для создания сопоставления list type -> index -> name (если вам нужно сопоставление index -> types containing strings, просто используйте кортеж вместо массива). С++ 17 может выглядеть следующим образом:

#include <type_traits>
#include <tuple>
#include <utility>
#include <iostream>

struct LicencesList{};
struct BundlesList{};
struct ProductsList{};
struct UsersList{};

using ListTypes = std::tuple<LicencesList, BundlesList, ProductsList, UsersList>;
constexpr const char *NameList[] = {"licences", "bundles", "products", "users"};

template <class Tup, class, class = std::make_index_sequence<std::tuple_size<Tup>::value>>
struct index_of;

template <class Tup, class T, std::size_t... Is>
struct index_of<Tup, T, std::index_sequence<Is...>> {
    static constexpr std::size_t value = ((std::is_same<std::tuple_element_t<Is, Tup>, T>::value * Is) + ...);
};


template<class ListT> static const char constexpr * GetNameOfList(void) {
  return NameList[index_of<ListTypes, ListT>::value];
}

int main() {
    constexpr const char *value = GetNameOfList<BundlesList>();
    std::cout << value << std::endl;
}

[live demo]

Если вы хотите поддерживать совместимость С++ 11, этот подход будет немного дольше (я использовал здесь ответ Кейси для реализации структуры index_of):

#include <type_traits>
#include <tuple>
#include <iostream>

struct LicencesList{};
struct BundlesList{};
struct ProductsList{};
struct UsersList{};

using ListTypes = std::tuple<LicencesList, BundlesList, ProductsList, UsersList>;
constexpr const char *NameList[] = {"licences", "bundles", "products", "users"};

template <class Tuple, class T>
struct index_of;

template <class T, class... Types>
struct index_of<std::tuple<T, Types...>, T> {
    static const std::size_t value = 0;
};

template <class T, class U, class... Types>
struct index_of<std::tuple<U, Types...>, T> {
    static const std::size_t value = 1 + index_of<std::tuple<Types...>, T>::value;
};


template<class ListT> static const char constexpr * GetNameOfList(void) {
  return NameList[index_of<ListTypes, ListT>::value];
}

int main() {
    constexpr const char *value = GetNameOfList<BundlesList>();
    std::cout << value << std::endl;
}

[live demo]