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
你的问题是递归调用是
Contains<is...>(j)
这会查找 模板 重载 Contains
.
您的基本情况:
bool Contains(int j) { return false; }
不是模板。所以最后一次调用,当包为空时:
Contains<>(j)
找不到 non-template。
有一些简单的修复方法。
最好的版本需要大于c++11的C++版本; 17 我认为:
template<int... is>
bool Contains(int j) { return ((is == j) || ...); }
这篇短小精悍。
简单的pre-c++14 ones generate O(n^2) total symbol length without jumping through extensive hoops. The c++17 one is O(n) total symbol length, much nicer. The c++14一个是钝的,也是O(n)的总符号长度。
所以这里有一些 c++11 适合中等长度的背包:
None c++11 个支持空包:
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) 的技术涉及对整数参数包进行二叉树重新打包。这是棘手和令人困惑的,我建议不要这样做。
最后,这是 c++14 中的一个 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;
}
不要问它是如何工作的。这是一种 c++17 故意过时的技术。
我正在尝试编写一个函数,如果在 运行 时传递的参数包含在编译时设置的整数列表中,则该函数的计算结果为真。我尝试在此处调整打印示例: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
你的问题是递归调用是
Contains<is...>(j)
这会查找 模板 重载 Contains
.
您的基本情况:
bool Contains(int j) { return false; }
不是模板。所以最后一次调用,当包为空时:
Contains<>(j)
找不到 non-template。
有一些简单的修复方法。
最好的版本需要大于c++11的C++版本; 17 我认为:
template<int... is>
bool Contains(int j) { return ((is == j) || ...); }
这篇短小精悍。
简单的pre-c++14 ones generate O(n^2) total symbol length without jumping through extensive hoops. The c++17 one is O(n) total symbol length, much nicer. The c++14一个是钝的,也是O(n)的总符号长度。
所以这里有一些 c++11 适合中等长度的背包:
None c++11 个支持空包:
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) 的技术涉及对整数参数包进行二叉树重新打包。这是棘手和令人困惑的,我建议不要这样做。
最后,这是 c++14 中的一个 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;
}
不要问它是如何工作的。这是一种 c++17 故意过时的技术。