【问题标题】:Use int-templated function with non-constexpr values使用具有非 constexpr 值的 int 模板函数
【发布时间】:2021-05-05 16:23:52
【问题描述】:

我有一些功能

template<int N>
auto foo();

我想用编译时未知的模板参数调用这个函数,但它们只能是数字 1 到 c(其中 c 是一个固定常数,例如 10)。有没有比以下更好的通用解决方案?

auto foo(int n)
{
  switch(n) {
    case 1:
      return foo<1>();
    case 2:
      return foo<2>();
...
    case 10:
      return foo<10>();
  }
}

如果将函数用于更大的整数集,则此解决方案会变得非常冗长。

此模板参数是必需的,因为该函数使用具有此类模板参数的类,其中 this 用于静态大小数组的大小。但这不应该与问题真正相关。我无法更改模板版本。

【问题讨论】:

  • 不确定如何在声明为 void 的函数中返回任何内容。这只是一个调度员吗?如果是这样,您要解决的问题是什么?
  • 模板参数必须在编译时就知道,你真的无能为力。显而易见的问题是,您真的需要 N 作为模板参数吗?
  • 你至少可以使用像#define CASE(num) case num : return foo&lt;num&gt;() 这样的宏,然后你就有switch(n) CASE(1); CASE(2); ...; CASE(N);
  • 你的意思是constraints
  • @tadman 我猜这是口味问题。在表达“现在我们完全委托给其他函数”时,我喜欢与返回值函数的一致性。

标签: c++ templates template-meta-programming


【解决方案1】:

当然:

template <int... Ns>
decltype(auto) dispatch_foo(int const n, std::integer_sequence<int, Ns...>) {
    static constexpr void (*_foos[])() { &foo<Ns>... };
    return _foos[n]();
}

template <int Nmax>
decltype(auto) dispatch_foo(int const n) {
    return dispatch_foo(n, std::make_integer_sequence<int, Nmax>{});
}

用法:

dispatch_foo<c>(n);

See it live on Wandbox

【讨论】:

  • 你能让foo成为模板参数吗?我太笨了,自己搞不清楚。
  • @Timo 不太...
  • @Timo there we go。有点笨拙,它仍然会使 Clang 崩溃,但 GCC 可以。
  • 很好,尽管您必须在这里使用包装器。我有类似的工作,但我不能直接用函数模板来做。
  • @Quentin 即使它在库中完成调用之类的事情,涉及包装器、SFINAE 变体、if constexpr 构造等,因为函数 mabe 的位置由可调用的,例如仿函数等。另一个如果我们将非静态成员函数视为可能的处理程序,那将是疯狂的程度。开发成本非常高。难怪像 Qt 这样的库会采用廉价的元对象编译方式。
【解决方案2】:

如果您可以调用加法辅助函数,那么结合模板折叠、三元运算符和逗号运算符使用整数序列(来自std::make_integer_sequence&lt;MAX&gt;{},其中MAX-1 是整数值的最大值)怎么样?

我的意思是……下面呢?

#include <iostream>
#include <utility>

template <int N>
void foo ()
 { std::cout << N << '\n'; }

template <int ... Is>
void foo (int n, std::integer_sequence<int, Is...>)
 { ((n == Is ? (foo<Is>(), 0) : 0), ...); }

void foo (int n)
 { foo(n, std::make_integer_sequence<int, 42>{}); }

int main()
 {
   foo(2); // print 2
   foo(3); // print 3
   foo(5); // print 5
   foo(7); // print 7
 }

如果您可以使用 C++20(因此模板 lambda),您可以避免额外的(外部)函数,并且您的 foo() 可以简单地编写

void foo (int n)
 { 
   [&]<int ... Is>(std::integer_sequence<int, Is...>)
        { ((n == Is ? (foo<Is>(), 0) : 0), ...); }
    (std::make_integer_sequence<int, 42>{});
 }

【讨论】:

    猜你喜欢
    • 2018-07-10
    • 1970-01-01
    • 1970-01-01
    • 2013-12-24
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 2013-08-26
    • 1970-01-01
    相关资源
    最近更新 更多