简单的方法
最简单的方法是在std::find 周围编写一个名为in() 的成员函数包装器,并使用一对迭代器来查找有问题的数据。我为此写了一个简单的template<class It> in(It first, It last) 成员函数
template<class It>
bool in(It first, It last) const
{
return std::find(first, last, data) != last;
}
如果你无权访问foo的源,你可以写一个签名template<class T> bool in(foo const&, std::initializer_list<T>)等的非成员函数,像这样调用它
in(f, {1, 2, 3 });
艰难的路
但是让我们完全过火:只需再添加两个public 重载:
- 一个采用
std::initializer_list 参数,该参数使用相应初始化列表参数的begin() 和end() 迭代器调用前一个参数。
- 一个用于任意容器作为输入,它将对
detail_in() 助手的另外两个private 重载执行一点标记调度:
- 一个重载使用尾随返回类型
decltype(c.find(data), bool()) 执行 SFINAE 技巧,如果相关容器 c 没有成员函数 find(),则将从重载集中删除,否则返回 bool(这是通过滥用decltype中的逗号运算符实现的)
- 一个后备重载,它简单地采用
begin() 和 end() 迭代器并委托给原始 in() 采用两个迭代器
因为detail_in() 帮助器的标签形成了一个继承层次结构(很像标准迭代器标签),第一个重载将匹配关联容器std::set 和std::unordered_set 及其多个表亲。所有其他容器,包括 C 数组、std::array、std::vector 和 std::list,都将匹配第二个重载。
#include <algorithm>
#include <array>
#include <initializer_list>
#include <type_traits>
#include <iostream>
#include <set>
#include <unordered_set>
#include <vector>
class foo
{
public:
int data;
template<class It>
bool in(It first, It last) const
{
std::cout << "iterator overload: ";
return std::find(first, last, data) != last;
}
template<class T>
bool in(std::initializer_list<T> il) const
{
std::cout << "initializer_list overload: ";
return in(begin(il), end(il));
}
template<class Container>
bool in(Container const& c) const
{
std::cout << "container overload: ";
return detail_in(c, associative_container_tag{});
}
private:
struct sequence_container_tag {};
struct associative_container_tag: sequence_container_tag {};
template<class AssociativeContainer>
auto detail_in(AssociativeContainer const& c, associative_container_tag) const
-> decltype(c.find(data), bool())
{
std::cout << "associative overload: ";
return c.find(data) != end(c);
}
template<class SequenceContainer>
bool detail_in(SequenceContainer const& c, sequence_container_tag) const
{
std::cout << "sequence overload: ";
using std::begin; using std::end;
return in(begin(c), end(c));
}
};
int main()
{
foo f{1};
int a1[] = { 1, 2, 3};
int a2[] = { 2, 3, 4};
std::cout << f.in({1, 2, 3}) << "\n";
std::cout << f.in({2, 3, 4}) << "\n";
std::cout << f.in(std::begin(a1), std::end(a1)) << "\n";
std::cout << f.in(std::begin(a2), std::end(a2)) << "\n";
std::cout << f.in(a1) << "\n";
std::cout << f.in(a2) << "\n";
std::cout << f.in(std::array<int, 3>{ 1, 2, 3 }) << "\n";
std::cout << f.in(std::array<int, 3>{ 2, 3, 4 }) << "\n";
std::cout << f.in(std::vector<int>{ 1, 2, 3 }) << "\n";
std::cout << f.in(std::vector<int>{ 2, 3, 4 }) << "\n";
std::cout << f.in(std::set<int>{ 1, 2, 3 }) << "\n";
std::cout << f.in(std::set<int>{ 2, 3, 4 }) << "\n";
std::cout << f.in(std::unordered_set<int>{ 1, 2, 3 }) << "\n";
std::cout << f.in(std::unordered_set<int>{ 2, 3, 4 }) << "\n";
}
Live Example -对于所有可能的容器- 为两个数字集打印 1 和 0。
std::initializer_list 重载的用例用于对您在调用代码中明确写出的小组数字进行成员资格测试。它具有O(N) 的复杂性,但避免了任何堆分配。
对于诸如大型集合的成员资格测试之类的任何繁重任务,您可以将数字存储在一个关联容器中,例如std::set,或其multi_set 或unordered_set 表亲。这将在存储这些数字时进入堆,但具有O(log N) 甚至O(1) 查找复杂性。
但如果你碰巧只有一个装满数字的序列容器,你也可以把它扔给班级,它会很乐意在O(N)时间为你计算成员资格。