C++ 模板元编程:查找可变参数类型列表是否包含值

Ant*_*ole 2 c++ variadic-templates

我正在尝试编写一个函数,如果在运行时传递的参数包含在编译时设置的整数列表中,则该函数的计算结果为 true。我尝试在这里调整打印示例:https://www.geeksforgeeks.org/variadic-function-templates-c/# :~:text=Variadic%20templates%20are%20class%20or,help%20to%20overcome%20this% 20期.

并尝试过这个:

bool Contains(int j) { return false; }

template<int i, int... is>
bool Contains(int j) { return i == j || Contains<is...>(j); }
Run Code Online (Sandbox Code Playgroud)

但是,它给了我一个编译器错误,指出“'包含':找不到匹配的重载函数”。

我尝试过摆弄尖括号,但似乎无法让它工作。

Yak*_*ont 6

你的问题是递归调用是

Contains<is...>(j)
Run Code Online (Sandbox Code Playgroud)

这会查找的模板重载Contains

您的基本情况:

bool Contains(int j) { return false; }
Run Code Online (Sandbox Code Playgroud)

不是模板。因此,当包为空时,最后的调用为:

Contains<>(j)
Run Code Online (Sandbox Code Playgroud)

找不到非模板。


有一些简单的修复方法。

最好的版本需要C++版本大于;17 我认为:

template<int... is>
bool Contains(int j) { return ((is == j) || ...); }
Run Code Online (Sandbox Code Playgroud)

这篇文章简短、简单、清晰。

简单的 pre- 生成 O(n^2) 总符号长度,而无需跳过大量的循环。c 符号总长度为 O(n),要好得多。c 是钝角的,但总符号长度也是 O(n) 。

因此,这里有一些适合适度长度的包的

都不支持空包:

template<class=void>
bool Contains(int j) { return false; }

template<int i, int... is>
bool Contains(int j) { return i == j || Contains<is...>(j); }
Run Code Online (Sandbox Code Playgroud)

它依赖于这样一个事实:除了空包之外,第一个重载永远不会被选择。(由于标准中的一个怪癖,对包装是否为空进行任何检查都是非法的)。

另一种不支持空包的方式是:

template<int i>
bool Contains(int j) { return i==j; }

template<int i0, int i1, int... is>
bool Contains(int j) { return Contains<i0>(j) || Contains<i1, is...>(j); }
Run Code Online (Sandbox Code Playgroud)

这比第一个更明确。

使总符号长度低于 O(n^2) 的技术涉及对整数参数包进行二叉树重新打包。这是棘手且令人困惑的,我建议不要这样做。

活生生的例子

中的一个 hacky ,它避免了 O(n^2) 符号长度问题:

template<int...is>
bool Contains(int j) {
  using discard=int[];
  bool result = false;
  (void)discard{0,((void)(result = result || (is==j)),0)...};
  return result;
}
Run Code Online (Sandbox Code Playgroud)

不要问它是如何工作的。故意废弃的技术。

  • 您能否暗示标准规定尺寸检查是非法的?无法使用“sizeof...(is) == 0”有什么意义? (3认同)