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

时间:2014-12-15 20:05:32

标签: c++ c++11 boost initializer-list

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

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,但它仅适用于字符串。

3 个答案:

答案 0 :(得分:6)

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

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

您只能使用标准库执行搜索,但这样做更加冗长。有两种选择:

  1. 使用lambda

    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)) { ... }
    
  3. Live demo

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

答案 1 :(得分:5)

如果您有的访问权限,则可以使用set的{​​{3}}返回bool,允许您这样做:

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

contains


否则,仅使用Live Example,您仍然可以使用set的{​​{3}},它只返回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))

答案 2 :(得分:1)

实际上,STL没有简单的std::contains()功能。最近,有关此主题的discussion on reddit

不幸的是,出现这种情况的原因是std::contains()被认为是有害的,因为它鼓励人们编写慢速算法。想想

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

此代码示例主要搜索两次正确的位置:一次进入包含,一次查找插入位置。

在我看来,拥有std::contains()仍然非常有帮助,但到目前为止还没有人相信还没有写出提案。

所以要么使用boost(正如此线程中的其他人所建议的那样),要么编写你自己已经做过的自己的函数: - )