Marcello Mura
Marcello Mura

Reputation: 21

Index of an element in a c++ integer_sequence at compile time

My problem is that I want to get the index of the element of an integer_sequence. The very naive version is below. I would like to have a meta-function taking using a variadic template on the enum type and taking as input the integer_sequence and the Type for which the index is required. Something similar exists in monster.hpp. I would better avoiding importing the whole package (it is not the smallest one) only for a function.

#include <iostream>
#include <utility>

using namespace std;
namespace animalsExperiment{

///////////////////////////////////////////////////////////////////////////////
enum class Animals {
    CAT = 15,
    DOG = 19,
    RABBIT = 43
};

///////////////////////////////////////////////////////////////////////////////
constexpr auto AllAnimals = integer_sequence<
        Animals,
        Animals::CAT,
        Animals::DOG,
        Animals::RABBIT
    >{};

template<Animals P>
constexpr int animalIndex = 0;

///////////////////////////////////////////////////////////////////////////////
template<>
constexpr int animalIndex<Animals::DOG> = 1;

///////////////////////////////////////////////////////////////////////////////
template<>
constexpr int animalIndex<Animals::RABBIT> = 2;

}

Upvotes: 0

Views: 469

Answers (2)

Marcello Mura
Marcello Mura

Reputation: 21

Using the nice Inputs I could come out with a potential solution

#include <utility>
#include <array>

using namespace std;

namespace enumExperiment{

///////////////////////////////////////////////////////////////////////////////
template<typename E>
auto AllValues = integer_sequence<
  E>{};  
  
///////////////////////////////////////////////////////////////////////////////
template<typename E, E Probe, auto... Values>
constexpr int valueIndexImpl(integer_sequence<E, Values...>) {
  std::array myValues{Values...};
  for (size_t i = 0; i < myValues.size(); i++)
    if (myValues[i] == Probe)
      return i;
  return -1;
}

///////////////////////////////////////////////////////////////////////////////
template<typename E, E Probe>
constexpr int valueIndex() {
  return valueIndexImpl<E,Probe>(AllValues<E>);
};

///////////////////////////////////////////////////////////////////////////////
enum class Animals {
  CAT = 15,
  DOG = 19,
  RABBIT = 43
};

///////////////////////////////////////////////////////////////////////////////
template<>
auto AllValues<Animals> = integer_sequence<
  Animals,
  Animals::CAT,
  Animals::DOG,
  Animals::RABBIT
>{};

///////////////////////////////////////////////////////////////////////////////
enum class Vegetables {
  EGGPLANT = 18,
  CARROT = 26,
  LETTUCE = 37
};

///////////////////////////////////////////////////////////////////////////////
template<>
 auto AllValues<Vegetables> = integer_sequence<
  Vegetables,
  Vegetables::EGGPLANT,
  Vegetables::CARROT,
  Vegetables::LETTUCE
>{};

static_assert(valueIndex<Animals, Animals::DOG>() == 1);
static_assert(valueIndex<Animals, Animals::RABBIT>() == 2);
static_assert(valueIndex<Animals, Animals::CAT>() == 0);
static_assert(valueIndex<Vegetables, Vegetables::CARROT>() == 1);

}

Still I am asking myself which is the metaprogramming syntax to get the enum class out of the enum class value. When I give Vegetables::CARROT the compiler must know that the enum class is Vegetables compile tyme reflection should be possible. Would be great to get a metafunction enumStructure on the value returning the value and the type (eunumStructure::value, eunumStructure::type). The Problem is that it would be based on a non-type template, but the type of the template should be in the result. Still this would make the external interface even simpler.

Upvotes: 0

康桓瑋
康桓瑋

Reputation: 42776

With some helper function

constexpr auto AllAnimals = integer_sequence<
  Animals,
  Animals::CAT,
  Animals::DOG,
  Animals::RABBIT
>{};

template<Animals P, auto... Values>
constexpr int animalIndexImpl(integer_sequence<Animals, Values...>) {
  std::array animals{Values...};
  for (size_t i = 0; i < animals.size(); i++)
    if (animals[i] == P)
      return i;
  return 0;
}

template<Animals P>
constexpr int animalIndex() {
  return animalIndexImpl<P>(AllAnimals);
};

static_assert(animalIndex<Animals::DOG>() == 1);
static_assert(animalIndex<Animals::RABBIT>() == 2);

Demo

Upvotes: 2

Related Questions