【问题标题】:switch over template parameters切换模板参数
【发布时间】:2021-02-12 14:01:47
【问题描述】:

当一个函数的模板参数的值只有在运行时才知道时,必须编写一个考虑所有可能参数的代码,并相应地调用该函数。

这个(过度)简化的例子说明了问题

#include <iostream>

template <int i>
void f()
{
   std::cout << i << std::endl;
}

int main()
{
   int i;
   std::cin >> i;
   if (i==0)
      f<0>();
   else if (i==1)
      f<1>();
   else if (i==2)
      f<2>();
   else
      std::cout << "invalid input" << std::endl;
}

这显然是非常乏味的,尤其是在有许多可能值的情况下。更糟糕的是,如果模板参数大于1,则需要考虑所有组合,例如:

#include <iostream>

template <int i, bool X>
void f()
{
   std::cout << i << ' ';
   if constexpr (X)
      std::cout << "true" << std::endl;
   else
      std::cout << "false" << std::endl;
}

int main()
{
   int i;
   char c;

   std::cin >> i;
   std::cin >> c;    
   if (c == 'y')
      {
         if (i==0)
            f<0,true>();
         else if (i==1)
            f<1,true>();
         else if (i==2)
            f<2,true>();
         else
            std::cout << "invalid input" << std::endl;
      }
   else
      {
         if (i==0)
            f<0,false>();
         else if (i==1)
            f<1,false>();
         else if (i==2)
            f<2,false>();
         else
            std::cout << "invalid input" << std::endl;
      }
}

(我当然知道滥用这个想法,即为所有模板组合实例化f,可能会导致代码膨胀。)

我正在寻找一个宏,它允许“基本上”用i 和x 一些运行时变量编写与f&lt;i, x&gt;() 等效的内容。

更具体地说,假设所有模板参数的值都是有限的,比如说

i = i1, i2, ... , in
x = x1, x2, ... , xn

我想要一个可以翻译这样的东西的宏

CallF(f, i, {i1,...,in}, x, {x1,...,xn}, par...)

进入

if (i==i1)
{
    if (x==x1)
      f<i1,x1>(par...);
    else if (x==x2)
      f<i1,x2>(par...);
    ....
}
else if (i==i2)
{
    if (x==x1)
      f<i2,x1>(par...);
    else if (x==x2)
      f<i2,x2>(par...);
    ....
}
else if (i==i3)
....

【问题讨论】:

  • 使用数组/矩阵/映射也可以完成这项工作 (std::array&lt;void(*)(), 3&gt; funcs[] = {&amp;f&lt;0&gt;, &amp;f&lt;1&gt;, &amp;f&lt;2&gt;}; if (i &lt; 3) { funcs[i]();})。该数组甚至可以通过编程方式构建
  • 正如问题中所写,这是一个简化的示例。我正在寻找一种方法来“自动化”编写耗尽所有允许的模板参数值的代码。
  • 如果你需要这样的东西,那些模板非类型参数可能应该是常规函数参数。

标签: c++ templates macros


【解决方案1】:

以下是对 1 个模板参数执行此操作的方法:

#include <cstdio>
#include <stdexcept>
#include <utility>

template <int i>
void f(char const* s, bool b, double d) {
  std::printf("%d -> %s %d %f\n", i, s, b, d);
}

template <class T, class ...Args>
[[noreturn]] void call_f(T&&, Args&&...) {
  throw std::invalid_argument{"Argument not in the list"};
}

template <auto first, auto... rest, class T, class ...Args>
void call_f(T const& t, Args&&... args) {
  if (t == first)
    f<first>(std::forward<Args>(args)...);
  else
    call_f<rest...>(t, std::forward<Args>(args)...);
}

int main() {
  int i = 2; // template argument

  // other arguments for f
  char const* s = "Hello";
  bool b = false;
  double d = 3.14;

  // decide which one to call at run time.
  call_f<1, 2, 3>(i, s, b, d);
}

【讨论】:

    猜你喜欢
    • 2023-01-12
    • 1970-01-01
    • 2013-09-15
    • 2022-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-31
    • 2012-01-03
    相关资源
    最近更新 更多