首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将每个枚举成员关联到一个类,并从该类获取泛型信息。

将每个枚举成员关联到一个类,并从该类获取泛型信息。
EN

Stack Overflow用户
提问于 2021-05-20 20:50:18
回答 1查看 159关注 0票数 0

假设我有很多音频效果到一个枚举:

代码语言:javascript
复制
enum AudioEffect {
    CHORUS,
    FILTER,
    GAIN,
    OSCILATOR,
    PHASER
};

对于每个类,都有一个类指定如何处理音频字节:

代码语言:javascript
复制
class ChorusProcessor  : public ProcessorBase
{
public:
    ChorusProcessor()
    {
    }
}

class FilterProcessor  : public ProcessorBase
{
public:
    FilterProcessor()
    {
    }
}

每个处理器类都有可以更改的参数,这些参数是音频控制器(静音/非静音、滑块等)。

如果不制作处理器实例,是否可以遍历枚举,并为每个枚举获取具有最小值和最大值的可控值列表?

我认为C++足够聪明,可以让我们做这些事情。我开始思考如何将ChorusChorusProcessorFilterFilterProcessor等联系起来。

然后,我会让所有处理器类派生自一个类,比如AudioEffectDescription,它有一些描述每个参数的constexpr

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-20 22:03:28

你可以用一些诡计来做这件事,但我不确定它到底有多有用。您必须面对的主要问题是,一般情况下,您的enum.不能轻松地迭代的所有值。由于普通enum的底层数据类型是整数,所以可以使用enum,但是对于手动设置值的任何enum,都会失败,例如

代码语言:javascript
复制
enum class AudioEffect {
  Chorus = 3,
  Filter = 6,
  Gain = 5,
  Oscillator = 2,
  Phaser = 1
};

通常,您必须创建一个额外的数据结构,如std::tuplestd::vector<AudioEffect>,添加所有可能的值并使用类似于可变模板的东西循环(一旦使用模板参数,普通循环就不够用了)。此外,在virtual static中,C++中没有、、、functions、这样的东西。

专业模板类

我想出的最好办法是:

  • 声明一个类template <AudioEffect E> class Processor专门为所有可能的模板参数指定。我添加了两个static constexpr函数来获取minmax。必须在所有专门化中宣布这一点。我使用了两个函数minmax,它们返回一个最小值和一个最大值,但是您可以返回一个包含有关不同限制的更多信息的std::string_view (或者在C++20中可以返回一个constexpr std::string)。 模板类处理器: ProcessorBase { };模板<>类Processor:ProcessorBase { public: //或用于打印该类的所有设置的单个函数--静态参数int min() {返回1;
  • 然后,我可以使用变量模板函数C++17折叠表达式打印的所有限制(这里假设template class Preprocessor的每个实例都有一个static constexpr函数min和另一个max ) 模板 std::string print() {std::<< << "\t min:“<< Processor::min() << ",\t max:”<< Processor::max() << std::endl),.);返回ss.str()};
  • 这个打印函数可以在主列表中调用,其中列出了所有可能的参数 << print() << std::endl;

在这里试试!

地图

另一种类似的方法是将enum映射到classes (不再需要专门化的模板)和traits (如这里 by )。

  • 定义类,如 类ChorusProcessor: ProcessorBase { public: static (){返回1;}静态参数max() {返回99;};
  • 然后,专门处理一个在enum值和classes之间映射的enum。 模板结构映射;template<>结构Map {使用类型= ChorusProcessor;};
  • 并再次引入打印功能,并使用各种模板,如 模板 std::string print() {std::string << ss;(ss << E << "\t min:“<< Map::type::min() << ",\t max:”<< Map::type:max()<< std::endl),.);返回ss.str();

在这里试试!

这与使用意见中提出的解决办法std::tuple非常相似。

代码语言:javascript
复制
using Processors = std::tuple<
  ChorusProcessor,
  FilterProcessor,
  GainProcessor,
  OscilatorProcessor,
  PhaserProcessor
>;

std::tuple_element_t<AudioEffect::Filter, Processors>::value

简约但肮脏的

如果您使用enum而没有显式地指定值,您也可以使用一个脏的解决方案,只提供enum (C++17)的第一个和最后一个值。

代码语言:javascript
复制
template <AudioEffect Begin, AudioEffect End>
std::string print() {
  std::stringstream ss;
  ss << Begin << "\t min: " << Processor<Begin>::min() << ",\t max: " << Processor<Begin>::max() << std::endl;
  if constexpr (Begin != End) {
    ss << print<static_cast<AudioEffect>(static_cast<int>(Begin)+1), End>();
  }
  return ss.str();
}

这样,您就可以先用enum值和的最后一个值调用它。

代码语言:javascript
复制
std::cout << print<AudioEffect::Chorus,AudioEffect::Phaser>() << std::endl;

在这里试试!

Enum反射

最后,利用GCC、Clang和MSVC编译器,提出了一种用__PRETTY_FUNCTION__ identifier (描述为这里 )获取某些枚举属性的方法。(在原始代码中有一些输入,但它不是constexpr,所以最好尝试一下这里。)使用它,您可以通过从0 循环到检测到的 enum 循环,完全消除BeginEnd。这有点复杂,所以我只留下代码给你试试看。使用它,您可以输出所有类,而无需显式地指定所有enum值:

代码语言:javascript
复制
std::cout << print<AudioEffect>() << std::endl;
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67627762

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档