首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >紧凑switch语句,重复使用相同的模板化函数

紧凑switch语句,重复使用相同的模板化函数
EN

Stack Overflow用户
提问于 2018-10-27 13:45:55
回答 4查看 127关注 0票数 2

我有以下带有相当大的switch语句的C++代码(我使用的是C++11编译器):

代码语言:javascript
运行
复制
void function(std::size_t i, other_args)
{
   switch(i)
   {
      case 0:
         templatedfunction<0>(other_args);
         break;
      case 1:
         templatedfunction<1>(other_args);
         break;
      case 2:
         templatedfunction<2>(other_args);
         break;
      ...............
      //lots of other cases here
      ...............
      case 100:
         templatedfunction<100>(other_args);
         break;

   }  

}

其中templatedfunction定义为

代码语言:javascript
运行
复制
template<std::size_t T>
void templatedfunction(other_args){
   //some code here
}

这是用于描述一个简单概念的大量代码行(即,使用与在其模板参数中传递的变量i相同的值调用templatedfunction )。在C++中有没有一种方法可以更紧凑地编写这段代码?应该有一种方法来实现这个长的switch语句,因为i是一个变量,而不是一个编译时间常数,所以compactly....Using templatedfunction<i>(other_args)将不会被编译。谢谢。

EN

回答 4

Stack Overflow用户

发布于 2018-10-27 16:38:25

非递归方法是创建函数指针数组,然后根据索引选择一个。

代码语言:javascript
运行
复制
template<std::size_t... Is>
void function_impl(std::index_sequence<Is...>, std::size_t i)
{
    using func_t = void(*)();
    static constexpr std::array<func_t, sizeof...(Is)> fnc_arr = {
        (&templatedfunction<Is>)...
    };

    fnc_arr[i]();
}

void function(std::size_t i)
{
    function_impl(std::make_index_sequence<100>(), i);
}

看看它是如何工作的,here。请注意,std::index_sequence是C++14,但可以很容易地在C++11中实现。

编辑:

下面是index_sequence的一个简单实现。请注意,它是非常糟糕的实现,因为它是递归的,深度是O(N),所以它不会让你做make_index_sequence<5000>你可以谷歌更好的实现。而且这只是index,而不是integer序列。

代码语言:javascript
运行
复制
template<std::size_t... Is>
struct index_sequence
{
    using type = std::size_t;

    static constexpr std::size_t size() noexcept
    {
        return sizeof...(Is);
    }
};

namespace detail
{
    template<std::size_t N, typename Seq>
    struct append;

    template<std::size_t N, std::size_t... Is>
    struct append<N, index_sequence<Is...>>
    {
        using type = index_sequence<Is..., N>;
    };


    template<std::size_t N>
    struct make_integer_seq
    {
        using type = typename append<N, typename make_integer_seq<N - 1>::type>::type;
    };

    template<>
    struct make_integer_seq<0>
    {
        using type = index_sequence<0>;
    };
}

template<std::size_t N>
using make_integer_sequence = typename detail::make_integer_seq<N - 1>::type;
票数 6
EN

Stack Overflow用户

发布于 2018-10-27 14:19:15

你可以这样做:

代码语言:javascript
运行
复制
template<std::size_t> struct Index_t { };

template<std::size_t i, class... Ts>
void function_impl(std::size_t index, Index_t<i>, const Ts&... ts)
{
    if (index == i)
        templatedfunction<i>(ts...);
    else
        function_impl(index, Index_t<i + 1>{}, ts...);
}

template<class... Ts>
void function_impl(std::size_t, Index_t<101>, const Ts&...)
{ }

template<class... Ts>
void function(std::size_t index, const Ts&... ts)
{ 
    function_impl(index, Index_t<0>{}, ts...);
}

优化器很可能将所有这些递归调用转换为一堆比较和跳转汇编指令。here就是一个简单的例子。

(在上面的代码中,我假设您的switch案例不会失败。)

票数 3
EN

Stack Overflow用户

发布于 2018-10-27 17:55:43

我喜欢Evg的解决方案(+1),但是是线性的,做了很多模板递归,可以超过递归限制(也许优化器可以避免这种情况,但我不喜欢依赖优化器)。

因此,我提出了Evg解决方案的对数变体:我们可以不在单个索引上迭代,而是在表示索引间隔的几个索引上迭代。我们可以根据i的值将这个区间一分为二。

我的意思是:给定以下function()

代码语言:javascript
运行
复制
void function (std::size_t i)
 {
   if ( i > 100 )
      std::cout << i << " is out of range" << std::endl;
   else
      function_impl<0, 101>(i); // as a switch from 0 to 100 (included)
 }

我们可以按如下方式编写function_impl()函数

代码语言:javascript
运行
复制
template <std::size_t L1, std::size_t L2>
void function_impl (std::size_t i)
 {
   if ( L1 == i )
      templatedFunction<L1>();
   else
    {
      constexpr auto LM { (L1 + L2) >> 1 }; 

      if ( i < LM )
         function_impl<L1, LM>(i);
      else
         function_impl<LM, L2>(i);
    }
 }

这大大减少了递归调用的数量。

下面是一个完整的编译示例

代码语言:javascript
运行
复制
#include <iostream>

template <std::size_t I>
void templatedFunction ()
 { std::cout << I << std::endl; }

template <std::size_t L1, std::size_t L2>
void function_impl (std::size_t i)
 {
   if ( L1 == i )
      templatedFunction<L1>();
   else
    {
      constexpr auto LM { (L1 + L2) >> 1 }; 

      if ( i < LM )
         function_impl<L1, LM>(i);
      else
         function_impl<LM, L2>(i);
    }

 }

void function (std::size_t i)
 {
   if ( i > 100 )
      std::cout << i << " is out of range" << std::endl;
   else
      function_impl<0, 101>(i);
 }

int main ()
 {
   for ( auto ui = 0u ; ui < 102u ; ++ui )
      function(ui);
 }
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53019091

复制
相关文章

相似问题

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