0

我有许多函数q1, q2,q3等,每个函数都有不同的返回类型(int, int64_t,std::string等)。

我还有一个print_result函数可以打印出他们的结果(以及他们运行的时间,但为了简单起见在这里进行了修剪):

template <typename T>
void print_result(T (*func)()) {
  T res = func();
  std::cout << res << std::endl;
}

我也有很大的 switch 语句来打印每个函数的结果:

switch (question_num) {
  case 1: print_result(q1); break;
  case 2: print_result(q2); break;
  case 3: print_result(q3); break;
  // ...
}

目标:我想用模板函数替换这个 switch 语句,以避免每次添加新函数时复制每一行。

我曾尝试查看C++ 模板实例化:避免长开关,但我是模板元编程的新手,所以不确定如何准确处理。

我目前无法编译的尝试:


template <<int, typename> ...> struct FuncList {};

template <typename T>
bool handle_cases(int, T, FuncList<>) {
  // default case
  return false;
}

template <<int I, typename T> ...S>
bool handle_cases(int i, T (*func)(), FuncList<T, S...>) {
  if (I != i) {
    return handle_cases(i, func, FuncList<S...>());
  }
  print_result(func);
  return true;
}

template <typename ...S>
bool handle_cases(int i, T (*func)()) {
  return handle_cases(i, func, FuncList<S...>());
}

// ...
  bool res = handle_cases<
    <1, q1>, <2, q2>, <3, q3>
  >(question_num);
// ...

我使用这个模板的理想方式显示在最后一行。

请注意,那里提供了从功能编号到功能的映射。函数编号是固定的,即q1映射到常量1并且在运行时不会改变。

编译错误(它可能相当基本,但我真的不太了解元编程):

error: expected unqualified-id before ‘&lt;<’ token
   17 | template <<int, typename> ...> struct FuncList {};
      |          ^~
4

4 回答 4

1
于 2020-07-10T10:07:08.250 回答
1

您可能喜欢不需要任何类型的运行时容器、中间不生成任何对象、甚至不生成数据表、生成的代码非常少且易于使用的版本:

// Example functions
int fint() { return 1; }
double fdouble() { return 2.2; }
std::string fstring() { return "Hallo"; }

// your templated result printer
     template < typename T>
void print_result( T parm )
{
    std::cout << "The result of call is " << parm << std::endl;
}

// lets create a type which is able to hold functions
template < auto ... FUNCS >
struct FUNC_CONTAINER
{
    static constexpr unsigned int size = sizeof...(FUNCS);
};

// and generate a interface to switch
template < unsigned int, typename T >
struct Switch_Impl;


template < unsigned int IDX, auto HEAD, auto ... TAIL >
struct Switch_Impl< IDX, FUNC_CONTAINER<HEAD, TAIL...>>
{
    static void Do( unsigned int idx )
    {
        if ( idx == IDX )
        {
            // Your function goes here
            print_result(HEAD());
        }
        else
        {
            if constexpr ( sizeof...(TAIL))
            {
                Switch_Impl< IDX+1, FUNC_CONTAINER<TAIL...>>::Do(idx);
            }
        }
    }
};

// a simple forwarder to simplify the interface
template < typename T>
struct Switch
{
    static void Do(unsigned int idx )
    {
        Switch_Impl< 0, T >::Do( idx );
    }
};

// and lets execute the stuff
int main()
{
    using FUNCS = FUNC_CONTAINER< fint, fdouble, fstring >;

    for ( unsigned int idx = 0; idx< FUNCS::size; idx++ )
    {
        Switch<FUNCS>::Do(idx);
    }
}
                                                                                                                                                                  
于 2020-07-10T10:29:57.217 回答
1
于 2020-07-10T12:17:02.867 回答
1

鉴于您“当前的尝试”......在我看来,您handle_cases几乎可以编写一个结构/类,如下所示

struct handle_cases
 {
   std::map<int, std::function<void()>> m;

   template <typename ... F>
   handle_cases (std::pair<int, F> const & ... p)
      : m{ {p.first, [=]{ print_result(p.second); } } ... }
    { }

   void operator() (int i)
    { m[i](); }
 };

在给定相应索引的情况下,在整数和print_result用函数调用的 lambda 和调用请求的 lambda之间有一个映射。operator()

您可以按如下方式创建该类的对象(不幸的是,我看不到避免使用std::make_pair()s 的方法)

handle_cases hc{ std::make_pair(10, q1),
                 std::make_pair(20, q2),
                 std::make_pair(30, q3),
                 std::make_pair(40, q4) };

并按如下方式使用它

hc(30);

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

#include <functional>
#include <map>
#include <iostream>

template <typename T>
void print_result (T(*func)())
 {
   T res = func();
   std::cout << res << std::endl;
 }

struct handle_cases
 {
   std::map<int, std::function<void()>> m;

   template <typename ... F>
   handle_cases (std::pair<int, F> const & ... p)
      : m{ {p.first, [=]{ print_result(p.second); } } ... }
    { }

   void operator() (int i)
    { m[i](); }
 };

char      q1 () { return '1'; }
int       q2 () { return 2; }
long      q3 () { return 3l; }
long long q4 () { return 4ll; }

int main ()
 {
   handle_cases hc{ std::make_pair(10, q1),
                    std::make_pair(20, q2),
                    std::make_pair(30, q3),
                    std::make_pair(40, q4) };

   hc(30);
 }
于 2020-07-10T18:50:27.620 回答