【问题标题】:Index of an element in a c++ integer_sequence at compile time编译时 c++ integer_sequence 中元素的索引
【发布时间】:2022-06-10 19:04:32
【问题描述】:

我的问题是我想获取 integer_sequence 元素的索引。非常幼稚的版本如下。我想要一个元函数在枚举类型上使用可变参数模板,并将 integer_sequence 和需要索引的类型作为输入。 Monster.hpp 中存在类似的东西。我最好避免只为一个函数导入整个包(它不是最小的)。

#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;

}

【问题讨论】:

  • 我会使用 -1std::numeric_limits&lt;int&gt;::max() 而不是 0 来表示“未找到”
  • 完全同意。这是一个简化的示例,实际上 0 是上例中 Animals::CAT 的正确值。我把它缩短了。对于所有情况,默认为无效值和显式表达式当然更干净。

标签: c++ c++17 variadic-templates constexpr template-meta-programming


【解决方案1】:

带有一些辅助功能

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

【讨论】:

  • 谢谢它已经更优雅了。 Enum 的类型仍然在模板中被硬编码。我想要一些独立于枚举类型的东西。可能不执行类型擦除,将枚举静态转换为 size_t,然后传递 size_t 而不是模板。
  • 使用 C++17 auto 模板参数创建值列表,例如 template&lt;auto...&gt; sequence,而不是旧的 integer_sequence
  • 我找不到关于模板 序列的任何文档来代替 integer_sequence。你有什么参考。
  • 可以推导出Animals作为模板参数:template&lt;typename T, T Probe, T... Values&gt; constexpr size_t indexOfImpl(std::integer_sequence&lt;T, Values...&gt;)
【解决方案2】:

使用不错的输入,我可以提出一个潜在的解决方案

#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);

}

我仍然在问自己,从枚举类值中获取枚举类的元编程语法是什么。当我给蔬菜::CARROT 时,编译器必须知道枚举类是蔬菜编译时间反射应该是可能的。 在返回值和类型(eunumStructure::value,eunumStructure::type)的值上获得元函数 enumStructure 会很棒。问题是它将基于非类型模板,但模板的类型应该在结果中。这仍然会使外部接口更加简单。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 2013-03-16
    • 1970-01-01
    • 2013-07-25
    • 1970-01-01
    相关资源
    最近更新 更多