检查元素是否在 std::initializer_list 中

Check whether an element is in std::initializer_list

本文关键字:initializer list std 元素 是否 检查      更新时间:2023-10-16

我希望能够用类似于以下Python代码编写C++:

if x in [1, 2, 3, 5] ...

测试元素是否包含在就地定义的一组硬编码值中。喜欢这个:

if (in(x, {1, 2, 3, 5})) ...

以下是 in 函数的可能实现:

template<class T>
bool in(const T& x, std::initializer_list<T> c)
{
  return std::find(c.begin(), c.end(), x) != c.end();
}

我的问题是:我真的必须自己编写这个函数吗?那里是否有任何默认实现?也许在提升?我检查了boost::contains,但它仅适用于字符串。

> 如果你可以访问 c++20,你可以使用 setcontains 它返回一个bool,允许你执行以下操作:

if(set{ 4, 8, 15, 16, 23, 42 }.contains(x))

现场示例


否则,仅使用 c++11,您仍然可以使用 setcount,它只返回 1 或 0,允许您执行以下操作:

if(set<int>{ 4, 8, 15, 16, 23, 42 }.count(x) > 0U)

现场示例


请记住,幻数可能会让您的观众感到困惑(并导致 5 季的迷失。
我建议将您的数字声明为const initializer_list<int>并给它们一个有意义的名称:

const auto finalCandidates{ 4, 8, 15, 16, 23, 42 };
if(cend(finalCandidates) != find(cbegin(finalCandidates), cend(finalCandidates), x))
boost::algorithm::contains不仅

适用于字符串,也适用于任何范围,即可以产生开始和结束迭代器的序列。要查找单个值,请按如下方式使用它:

auto l = {1,2,3,4};
auto l1 = {2};      // thing you want to find
if(boost::algorithm::contains(l, l1)) { ... }

您只能使用标准库执行搜索,但这样做会更加冗长。有几个选项是:

  1. 使用λ

    if(std::any_of(l.begin(), l.end(), 
                   [](int i){ return i == 2; })) { ... }
    
  2. 使用std::bind

    using std::placeholders::_1;
    if(std::any_of(l.begin(), l.end(), 
                   std::bind(std::equal_to<>(), 2, _1)) { ... }
    

现场演示

请注意,std::equal_to<>()是仅限 C++14 的选项。对于 C++11 编译器,请使用 std::equal_to<int>()

事实上,STL没有一个简单的std::contains()函数。最近,在reddit上有一个关于这个话题的讨论。

不幸的是,由此得出的结果是 拥有std::contains()被认为是有害的,因为它鼓励人们编写缓慢的算法。以

if (!std::contains(my_set.begin(), my_set.end(), entry)) {
    my_set.insert(entry);
}

此代码示例实质上搜索正确位置两次:一次在包含中,一次查找插入位置。

在我看来,拥有std::contains()仍然会很有帮助,但到目前为止还没有人被说服写提案。

因此,要么使用 boost(如此线程中的其他人所建议的那样),要么编写您自己的函数,您基本上已经这样做了:-)