使用枚举值作为模板函数的模板参数在运行时进行元编程。

huangapple go评论83阅读模式
英文:

Metaprogram to use enumerator value as template parameter of a template function at runtime

问题

我想编写一个bar函数,为my_enum的每个元素专门为foo函数,并根据bar函数的参数值在运行时调用其中一个函数。最简单的解决方案是编写一个开关,并手动添加所有情况:

int bar(my_enum value) {
    switch (value) {
    using m = my_enum;
    case m::ONE:
        return foo<m::ONE>();
    case my_enum::TWO:
        return foo<m::TWO>();
    case my_enum::THREE:
        return foo<m::THREE>();
    }
}

为了处理意外的值,还可以添加开关的默认值。不幸的是,对于非常长的枚举值,这种解决方案会导致非常冗长且重复的代码,难以维护。

是否有元编程解决方案可以简化这段代码,例如使用Boost Hana或Boost MPL?

英文:

Let't suppose I have this code:

// the enumerator
enum class my_enum {
	ONE,
	TWO,
	THREE
};

// the function
template &lt;my_enum E&gt;
int foo() {
	return 0;
}

// a specialization
template&lt;&gt;
int foo&lt;my_enum::TWO&gt;() {
	return 1;
}

I would like to write a bar function that specializes foo for each element of my_enum, and that calls, at run-time, one of those functions based on the value of an argument of bar. The simplest solution is to write a switch and manually adding all the cases:

int bar(my_enum value) {
	switch (value) {
	using m = my_enum;
	case m::ONE:
		return foo&lt;m::ONE&gt;();
	case my_enum::TWO:
		return foo&lt;m::TWO&gt;();
	case my_enum::THREE:
		return foo&lt;m::THREE&gt;();
	}
}

with some additional tricks to handle a unexpected value adding a default value of the switch. Unfortunately, for very long enumerators this solution brings to very long and redundant code, that is difficult to be maintained.

Is there any metaprogramming solution to simplify this code, for example using Boost Hana or Boost MPL?

答案1

得分: 1

Here's the translated code portion:

如果枚举值如您的示例一样从零开始且连续... 给定以下助手函数:

template <std::size_t ... Is>
std::array<int(*)(void), sizeof...(Is)>
    getFuncArray (std::index_sequence<Is...>)
 { return {{ &foo<static_cast<my_enum>(Is)>... }}; }

您可以在 bar() 中添加一个静态函数数组,并根据输入调用正确的函数。

我的意思是:

int bar (my_enum value)
 {
   static auto const arrF
      = getFuncArray(std::make_index_sequence<
                        1u+static_cast<std::size_t>(my_enum::THREE)>{});

   return arrF[static_cast<std::size_t>(value)]();
 }
英文:

If the enum values are, as in your example, starting from zero and consecutive... given an helper function as follows

template &lt;std::size_t ... Is&gt;
std::array&lt;int(*)(void), sizeof...(Is)&gt;
    getFuncArray (std::index_sequence&lt;Is...&gt;)
 { return {{ &amp;foo&lt;static_cast&lt;my_enum&gt;(Is)&gt;... }}; }

you can add, in bar(), a static array of functions and call the correct one according the input.

I mean

int bar (my_enum value)
 {
   static auto const arrF
      = getFuncArray(std::make_index_sequence&lt;
                        1u+static_cast&lt;std::size_t&gt;(my_enum::THREE)&gt;{});

   return arrF[static_cast&lt;std::size_t&gt;(value)]();
 }

huangapple
  • 本文由 发表于 2020年1月3日 21:33:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/59579517.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定