代码之家  ›  专栏  ›  技术社区  ›  Leon

如何简化搜索算法返回的迭代器是否有效的检查?

  •  0
  • Leon  · 技术社区  · 8 年前

    昨天,我很幸运地看到一个问题存在了很短一段时间,在我写答案的时候被删除了(我想这个问题是由作者删除的,他/她的建议没有多大意义,评论员认为他/她的提议是有道理的)。我正在以一种稍微更一般的方式重新表述这个问题,并提供我的答案。其他想法和/或指向我想法的现有实现的指针(我没能很快找到)也很受欢迎。

    find() 属于 std::map ,但也可以通过 std::find std::lower_bound 算法):

    const auto it = map.find(key);     // 1
    if ( it != map.end() )             // 2
    {
        do something with it
    }
    

    const auto it = p->getMappingFor(currentConfig()->whatever()).find(key);
    

    有没有一种方法可以将上例中的第1行和第2行折叠为一行,并且只引用一次地图对象?

    编辑1:

    简化的动机 查找并检查 模式与导致 range-based for loop 作为更方便的 traditional for loop .

    3 回复  |  直到 8 年前
        1
  •  1
  •   R Sahu    8 年前

    有没有一种方法可以将下面示例中的第1行和第2行折叠为一行,并且只引用一次地图对象?

    我不清楚这其中的动机。将多个查询组合成一行程序会导致代码更难理解和调试。我建议将2号班轮改为3号班轮,而不是1号班轮。

    auto const& theMap = p->getMappingFor(currentConfig()->whatever());
    auto const it = theMap.find(key);
    if ( it != theMap.end() )
    {
       ...
    }
    
        2
  •  0
  •   Leon    8 年前

    在容器中查找内容并立即检查返回迭代器的有效性的最短形式是:

    if (const auto it = find_in(container, something))
    {
        do something with it
    }
    

    要编译此文件 it 必须可转换为 bool (不用说 必须从底层搜索操作返回的常规迭代器类型派生)。下面的代码包含 find_in() 实用程序 std::vector std::map 。为其他容器添加重载很简单。

    #include <algorithm>
    #include <vector>
    #include <map>
    #include <iostream>
    
    template<class It>
    class OptionalIterator : public It
    {
        It end_;
    
    public:
        OptionalIterator(It it, It end) : It(it), end_(end) {}
    
        explicit operator bool() const
        {
            return static_cast<const It&>(*this) != end_;
        }
    };
    
    ////////////////////// find_in() a range ///////////////////////////////////
    
    template<class It, class X>
    OptionalIterator<It>
    find_in(It start, It end, const X& x)
    {
        return OptionalIterator<It>(std::find(start, end, x), end);
    }
    
    ////////////////////// find_in() a std::vector /////////////////////////////
    
    template<class T, class A, class X>
    OptionalIterator<typename std::vector<T, A>::const_iterator>
    find_in(const std::vector<T, A>& v, const X& x)
    {
        return find_in(v.begin(), v.end(), x);
    }
    
    template<class T, class A, class X>
    OptionalIterator<typename std::vector<T, A>::iterator>
    find_in(std::vector<T, A>& v, const X& x)
    {
        return find_in(v.begin(), v.end(), x);
    }
    
    ////////////////////// find_in() a std::map ////////////////////////////////
    
    template<class K, class V, class C, class A, class X>
    OptionalIterator<typename std::map<K, V, C, A>::const_iterator>
    find_in(const std::map<K, V, C, A>& m, const X& x)
    {
        typedef typename std::map<K, V, C, A>::const_iterator It;
        return OptionalIterator<It>(m.find(x), m.end());
    }
    
    template<class K, class V, class C, class A, class X>
    OptionalIterator<typename std::map<K, V, C, A>::iterator>
    find_in(std::map<K, V, C, A>& m, const X& x)
    {
        typedef typename std::map<K, V, C, A>::iterator It;
        return OptionalIterator<It>(m.find(x), m.end());
    }
    
    ////////////////////////////////////////////////////////////////////////////
    
    int main()
    {
        std::vector<int> v{2, 4, 1, 3};
        if ( const auto it = find_in(v, 4) )
                std::cout << "4 in v is at index " << it - v.begin() << std::endl;
    
        std::map<int, int> m{{1, 23}, {4, 56}};
        if ( const auto it = find_in(m, 4) )
                std::cout << "m[4]=" << it->second << std::endl;
    
        return 0;
    }
    
        3
  •  0
  •   Johan Lundberg    8 年前

    使用C++17,我们将 If statements with initializer .

    然后我们可以写

    if (const auto it = theMap.find(key); it != theMap.end() ) {
       ...
    }
    

    这样做的好处是迭代器位于 if 只有,包括可能的 else 条款