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

C++ template meta-programming: find out if variadic type list contains value

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

并尝试过这个:

bool Contains(int j) { return false; }

template<int i, int... is>
bool Contains(int j) { return i == j || Contains<is...>(j); }

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

我试过摆弄尖括号,但似乎无法正常工作。

你可以用 fold expression (C++17) 实现你想要的:

template<int... is>
bool Contains(int j) { return ((is == j) || ...); 

这样调用:

std::cout << std::boolalpha << Contains<1, 2, 3>(1) << "\n"; // true
std::cout << std::boolalpha << Contains<1, 2, 3>(4);         // false

Live Demo

你的问题是递归调用是

Contains<is...>(j)

这会查找 模板 重载 Contains.

您的基本情况:

bool Contains(int j) { return false; }

不是模板。所以最后一次调用,当包为空时:

Contains<>(j)

找不到 non-template。


有一些简单的修复方法。

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

template<int... is>
bool Contains(int j) { return ((is == j) || ...); }

这篇短小精悍。

简单的pre- ones generate O(n^2) total symbol length without jumping through extensive hoops. The one is O(n) total symbol length, much nicer. The 一个是钝的,也是O(n)的总符号长度。

所以这里有一些 适合中等长度的背包:

None 个支持空包:

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

template<int i, int... is>
bool Contains(int j) { return i == j || Contains<is...>(j); }

它依赖于这样一个事实,即除了空包外,永远不会选择第一个过载。 (由于标准中的一个怪癖,检查包装是否为空是非法的)。

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

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); }

比第一个更明确。

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

Live example.

最后,这是 中的一个 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;
}

不要问它是如何工作的。这是一种 故意过时的技术。