想要类型的constexpr开关案例

时间:2016-11-22 15:55:55

标签: c++ templates metaprogramming

我目前正在做这个技巧,以获得基于类型的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 :: conditional需要一些类型,所以我们需要一些类来做这个技巧:

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

例如。

3 个答案:

答案 0 :(得分:21)

我认为使用模板专业化会更容易

示例代码:

document.querySelectorAll('iframe')

答案 1 :(得分:13)

你不需要诉诸元编程,普通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;
}

See it live on Coliru

答案 2 :(得分:3)

您可以创建constexpr字符串数组和列表类型元组来创建映射list type -> index -> name(如果您需要映射index -> types containing strings,只需使用元组而不是数组)。 c ++ 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]

如果你想保持c ++ 11的兼容性,那么这种方法会稍长一些(我在这里使用Casey's answer来实现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]