[C++]一份Linq to object的C++实现

几个月的构想+0.5小时的设计+4小时的linq.h编码+3小时的测试编码。

大量使用C++11的特性,在GCC 4.7.2下编译通过。

关于实现相关的描述就不说了,我表达能力差,恐怕讲清楚还需要好几个小时。具体使用参见测试码。

上代码:

(1) linq.h

[C++]一份Linq to object的C++实现
#define LINQ_H

include

include

include

include

include

include

<set>

include

include

/
* ISSUES:
* 1. an non-delay action will break of the delay list: dataSource changed,
* but query doesn't know. (see @ non-delay)
/

template
struct DeclareType
{
typedef
typename std::remove_cv
<
typename std::remove_reference
<
typename std::remove_cv
::type>::type>::type Type;
};

template class Enumerable;
template

auto range(T end)
-> Enumerable;
template

auto
from(const ContainerT& c) -> Enumerable<
typename DeclareType
::Type >;

template
class Enumerable
{
private:
typedef std::function
<std::pair<bool, T>()> ClosureT;
public:
struct iterator
{
public:
typedef std::forward_iterator_tag iterator_category;
typedef T value_type;
typedef
int difference_type;
typedef T
pointer;
typedef T
& reference;
public:
iterator(): m_advanced(
false){}
iterator(
const ClosureT& c): m_closure(c), m_advanced(true)
{
assert(m_closure);
}
iterator
& operator ++ ()
{
_doAdvance();
assert(m_closure
&& !m_advanced);
m_advanced
= true;
return
this;
}
iterator
operator ++ (int)
{
iterator r(
this);
++
this;
return r;
}
const T& operator * () const
{
_doAdvance();
return m_v;
}
bool operator == (const iterator& o) const
{
_doAdvance();
o._doAdvance();
// just for exp: begin == end
return m_closure == nullptr && o.m_closure == nullptr;
}
bool operator != (const iterator& o) const
{
return !(*this == o);
}

</span><span>private</span><span>:
    </span><span>void</span> _doAdvance() <span>const</span><span>
    {
        const_cast</span><iterator*>(<span>this</span>)-&gt;<span>_doAdvance();
    }
    </span><span>void</span><span> _doAdvance()
    {
        </span><span>if</span> (!m_advanced) <span>return</span><span>;
        m_advanced </span>= <span>false</span><span>;
        assert(m_closure);
        auto r </span>=<span> m_closure();
        </span><span>if</span> (!r.first) m_closure =<span> nullptr;
        </span><span>else</span> m_v =<span> r.second;
    }

    ClosureT m_closure;
    T m_v;
    </span><span>bool</span><span> m_advanced;
};

public:
Enumerable(
const ClosureT& c):
m_closure(c)
{ }

Enumerable() </span>= <span>default</span><span>;

public:
iterator begin()
const
{
return iterator(m_closure);
}
iterator end()
const
{
return iterator();
}

public:
template

auto
select(const FuncT &f) const -> Enumerable0))>::Type>
{
typedef typename DeclareType
<decltype(f((t)0))>::Type RType;
auto iter
= this->begin(), end = this->end();
return Enumerable(iter, end, f mutable
{
if (iter == end) return std::make_pair(false, RType());
return std::make_pair(true, f(*iter++));
});
}

template</span><typename><span>
auto </span><span>where</span>(<span>const</span> FuncT&amp; f) <span>const</span> -&gt;<span> Enumerable
{
    auto iter </span>= <span>this</span>-&gt;begin(), end = <span>this</span>-&gt;<span>end();
    </span><span>return</span><span> Enumerable([iter, end, f]() mutable
    {
        </span><span>while</span> (iter != end &amp;&amp; !f(*iter)) ++<span>iter;
        </span><span>if</span> (iter == end) <span>return</span> std::make_pair(<span>false</span><span>, T());
        </span><span>return</span> std::make_pair(<span>true</span>, *iter++<span>);
    });
}

template</span><typename><span>
auto all(</span><span>const</span> FuncT&amp; f) <span>const</span> -&gt; <span>bool</span><span>
{
    </span><span>for</span> (auto i : *<span>this</span><span>) {
        </span><span>if</span> (!f(i)) <span>return</span> <span>false</span><span>;
    }
    </span><span>return</span> <span>true</span><span>;
}

template</span><typename><span>
auto any(</span><span>const</span> FuncT&amp; f) <span>const</span> -&gt; <span>bool</span><span>
{
    </span><span>for</span> (auto i : *<span>this</span><span>) {
        </span><span>if</span> (f(i)) <span>return</span> <span>true</span><span>;
    }
    </span><span>return</span> <span>false</span><span>;
}

template</span><typename><span>
auto cast() </span><span>const</span> -&gt; Enumerable<destt><span>
{
    auto iter </span>= <span>this</span>-&gt;begin(), end = <span>this</span>-&gt;<span>end();
    </span><span>return</span> Enumerable<destt><span>([iter, end]() mutable
    {
        </span><span>if</span> (iter == end) <span>return</span> std::make_pair(<span>false</span><span>, DestT());
        </span><span>return</span> std::make_pair(<span>true</span>, DestT(*iter++<span>));
    });
}

auto average() </span><span>const</span> -&gt;<span> T
{
    T v </span>=<span> T();
    </span><span>int</span> n = <span>0</span><span>;
    </span><span>for</span> (auto i : *<span>this</span><span>) {
        v </span>+=<span> i;
        </span>++<span>n;
    }
    assert(n </span>&gt; <span>0</span><span>);
    </span><span>return</span> v /<span> n;
}

auto contain(</span><span>const</span> T&amp; v) <span>const</span> -&gt; <span>bool</span><span>
{
    </span><span>for</span> (auto i : *<span>this</span><span>) {
        </span><span>if</span> (i == v) <span>return</span> <span>true</span><span>;
    }
    </span><span>return</span> <span>false</span><span>;
}

auto count(</span><span>const</span> T&amp; v) <span>const</span> -&gt; <span>int</span><span>
{
    </span><span>return</span> count([v](T i){ <span>return</span> i ==<span> v;});
}

template</span><typename><span>
auto count(</span><span>const</span> FuncT&amp; f, typename std::enable_if<!std::is_convertible<FuncT, T>::value&gt;::type* = <span>0</span>) <span>const</span> -&gt; <span>int</span><span>
{
    </span><span>int</span> n = <span>0</span><span>;
    </span><span>for</span> (auto i : *<span>this</span><span>) {
        </span><span>if</span> (f(i)) ++<span>n;
    }
    </span><span>return</span><span> n;
}

auto first() </span><span>const</span> -&gt;<span> T
{
    </span><span>return</span> *<span>this</span>-&gt;<span>begin();
}

auto last() </span><span>const</span> -&gt;<span> T
{
    T v;
    </span><span>for</span> (auto i : *<span>this</span>) v =<span> i;
    </span><span>return</span><span> v;
}

auto head(</span><span>int</span> n) <span>const</span> -&gt;<span> Enumerable
{
    auto iter </span>= <span>this</span>-&gt;begin(), end = <span>this</span>-&gt;<span>end();
    </span><span>return</span><span> Enumerable([iter, end, n]() mutable
    {
        </span><span>if</span> (--n &lt; <span>0</span> || iter == end) <span>return</span> std::make_pair(<span>false</span><span>, T());
        </span><span>return</span> std::make_pair(<span>true</span>, *iter++<span>);
    });
}

auto tail(</span><span>int</span> n) <span>const</span> -&gt;<span> Enumerable
{
    </span><span>int</span> sz = (<span>int</span>)std::vector<t>(<span>this</span>-&gt;begin(), <span>this</span>-&gt;<span>end()).size();
    n </span>=<span> std::min(n, sz);
    auto iter </span>= <span>this</span>-&gt;begin(), end = <span>this</span>-&gt;<span>end();
    std::advance(iter, sz </span>-<span> n);
    </span><span>return</span><span> Enumerable([iter, end]() mutable
    {
        </span><span>if</span> (iter == end) <span>return</span> std::make_pair(<span>false</span><span>, T());
        </span><span>return</span> std::make_pair(<span>true</span>, *iter++<span>);
    });
}

</span><span>//</span><span> @ non-delay</span>
template<typename><span>
auto groupBy(</span><span>const</span> FuncT &amp;f) <span>const</span> -&gt; Enumerable&lt;<span>
    std::pair</span><typename>0))&gt;::Type, Enumerable&gt;&gt;<span>
{
    typedef typename DeclareType</span><decltype(f(*(t*)<span>0))&gt;<span>::Type RType;
    typedef std::pair</span><rtype,><span> RPair;

    std::map</span><rtype,>&gt;<span> m;
    </span><span>for</span> (auto i : *<span>this</span><span>) {
        m[f(i)].push_back(i);
    }

    std::shared_ptr</span><std::map<rtype,>&gt; m2(<span>new</span> std::map<rtype,><span>());
    </span><span>for</span><span> (auto i : m) {
        (</span>*m2)[i.first] = <span>from</span><span>(i.second).reserve();
    }

    auto iter </span>= m2-&gt;<span>begin();
    </span><span>return</span> Enumerable<rpair><span>([iter, m2]() mutable
    {
        </span><span>if</span> (iter == m2-&gt;end()) <span>return</span> std::make_pair(<span>false</span><span>, RPair());
        </span><span>return</span> std::make_pair(<span>true</span>, RPair(*iter++<span>));
    });
}

template</span><typename><span>
auto takeUntil(</span><span>const</span> FuncT&amp; f) <span>const</span> -&gt;<span> Enumerable
{
    auto iter </span>= <span>this</span>-&gt;begin(), end = <span>this</span>-&gt;<span>end();
    </span><span>return</span><span> Enumerable([iter, end, f]() mutable
    {
        </span><span>if</span> (iter == end) <span>return</span> std::make_pair(<span>false</span><span>, T());
        T r </span>= *iter++<span>;
        </span><span>if</span> (f(r)) <span>return</span> std::make_pair(<span>false</span><span>, T());
        </span><span>return</span> std::make_pair(<span>true</span><span>, r);
    });
}

template</span><typename><span>
auto skipUntil(</span><span>const</span> FuncT&amp; f) <span>const</span> -&gt;<span> Enumerable
{
    auto iter </span>= <span>this</span>-&gt;begin(), end = <span>this</span>-&gt;<span>end();
    </span><span>while</span> (iter != end &amp;&amp; !f(*iter)) ++<span>iter;
    </span><span>return</span><span> Enumerable([iter, end]() mutable
    {
        </span><span>if</span> (iter == end) <span>return</span> std::make_pair(<span>false</span><span>, T());
        </span><span>return</span> std::make_pair(<span>true</span>, *iter++<span>);
    });
}

auto max() </span><span>const</span> -&gt;<span> T
{
    auto iter </span>= <span>this</span>-&gt;begin(), end = <span>this</span>-&gt;<span>end();
    assert(iter </span>!=<span> end);
    T v </span>= *iter++<span>;
    </span><span>while</span> (iter != end) v = std::max(v, *iter++<span>);
    </span><span>return</span><span> v;
}

auto min() </span><span>const</span> -&gt;<span> T
{
    auto iter </span>= <span>this</span>-&gt;begin(), end = <span>this</span>-&gt;<span>end();
    assert(iter </span>!=<span> end);
    T v </span>= *iter++<span>;
    </span><span>while</span> (iter != end) v = std::min(v, *iter++<span>);
    </span><span>return</span><span> v;
}

template</span><typename><span>
auto reduce(</span><span>const</span> FuncT&amp; f, T v = T()) <span>const</span> -&gt;<span> T
{
    </span><span>for</span> (auto i : *<span>this</span>) v =<span> f(v, i);
    </span><span>return</span><span> v;
}

</span><span>//</span><span> @ non-delay</span>
auto reverse() <span>const</span> -&gt;<span> Enumerable
{
    std::shared_ptr</span><std::vector<t>&gt; v(<span>new</span> std::vector<t>(<span>this</span>-&gt;begin(), <span>this</span>-&gt;<span>end()));
    auto iter </span>= v-&gt;<span>rbegin();
    </span><span>return</span><span> Enumerable([iter, v]() mutable
    {
        </span><span>if</span> (iter == v-&gt;rend()) <span>return</span> std::make_pair(<span>false</span><span>, T());
        </span><span>return</span> std::make_pair(<span>true</span>, *iter++<span>);
    });
}

</span><span>//</span><span> @ non-delay</span>
auto reserve() <span>const</span> -&gt;<span> Enumerable
{
    std::shared_ptr</span><std::vector<t>&gt; v(<span>new</span> std::vector<t>(<span>this</span>-&gt;begin(), <span>this</span>-&gt;<span>end()));
    auto iter </span>= v-&gt;<span>begin();
    </span><span>return</span><span> Enumerable([iter, v]() mutable
    {
        </span><span>if</span> (iter == v-&gt;end()) <span>return</span> std::make_pair(<span>false</span><span>, T());
        </span><span>return</span> std::make_pair(<span>true</span>, *iter++<span>);
    });
}

auto sort() </span><span>const</span> -&gt;<span> Enumerable
{
    </span><span>return</span> sort(std::less<t><span>());
}

</span><span>//</span><span> @ non-delay</span>
template<typename><span>
auto sort(</span><span>const</span> FuncT&amp; f) <span>const</span> -&gt;<span> Enumerable
{
    std::shared_ptr</span><std::vector<t>&gt; v(<span>new</span> std::vector<t>(<span>this</span>-&gt;begin(), <span>this</span>-&gt;<span>end()));
    std::sort(v</span>-&gt;begin(), v-&gt;<span>end(), f);
    auto iter </span>= v-&gt;<span>begin();
    </span><span>return</span><span> Enumerable([iter, v]() mutable
    {
        </span><span>if</span> (iter == v-&gt;end()) <span>return</span> std::make_pair(<span>false</span><span>, T());
        </span><span>return</span> std::make_pair(<span>true</span>, *iter++<span>);
    });
}

</span><span>//</span><span> @ non-delay</span>
auto intersect(<span>const</span> Enumerable&amp; o) <span>const</span> -&gt;<span> Enumerable
{
    std::shared_ptr</span><std::<span>set<t>&gt; s1(<span>new</span> std::<span>set</span><t>(<span>this</span>-&gt;begin(), <span>this</span>-&gt;<span>end()));
    std::shared_ptr</span><std::<span>set<t>&gt; s2(<span>new</span> std::<span>set</span><t><span>(o.begin(), o.end()));
    auto iter </span>= s1-&gt;<span>begin();
    </span><span>return</span><span> Enumerable([iter, s1, s2]() mutable
    {
        </span><span>while</span> (iter != s1-&gt;end() &amp;&amp; s2-&gt;count(*iter) == <span>0</span>) ++<span>iter;
        </span><span>if</span> (iter == s1-&gt;end()) <span>return</span> std::make_pair(<span>false</span><span>, T());
        </span><span>return</span> std::make_pair(<span>true</span>, *iter++<span>);
    });
}

</span><span>//</span><span> @ non-delay</span>
auto _union(<span>const</span> Enumerable&amp; o) <span>const</span> -&gt;<span> Enumerable
{
    std::shared_ptr</span><std::<span>set<t>&gt; s(<span>new</span> std::<span>set</span><t>(<span>this</span>-&gt;begin(), <span>this</span>-&gt;<span>end()));
    s</span>-&gt;<span>insert(o.begin(), o.end());
    auto iter </span>= s-&gt;<span>begin();
    </span><span>return</span><span> Enumerable([iter, s]() mutable
    {
        </span><span>if</span> (iter == s-&gt;end()) <span>return</span> std::make_pair(<span>false</span><span>, T());
        </span><span>return</span> std::make_pair(<span>true</span>, *iter++<span>);
    });
}

auto unique() </span><span>const</span> -&gt;<span> Enumerable
{
    std::</span><span>set</span><t><span> s;
    auto iter </span>= <span>this</span>-&gt;begin(), end = <span>this</span>-&gt;<span>end();
    </span><span>return</span><span> Enumerable([iter, end, s]() mutable
    {
        </span><span>while</span> (iter != end &amp;&amp; s.count(*iter) &gt; <span>0</span>) ++<span>iter;
        </span><span>if</span> (iter == end) <span>return</span> std::make_pair(<span>false</span><span>, T());
        s.insert(</span>*<span>iter);
        </span><span>return</span> std::make_pair(<span>true</span>, *iter++<span>);
    });
}

</span><span>//</span><span> @ non-delay</span>
auto random() <span>const</span> -&gt;<span> Enumerable
{
    std::shared_ptr</span><std::vector<t>&gt; v(<span>new</span> std::vector<t>(<span>this</span>-&gt;begin(), <span>this</span>-&gt;<span>end()));
    std::random_shuffle(v</span>-&gt;begin(), v-&gt;<span>end());
    auto iter </span>= v-&gt;<span>begin();
    </span><span>return</span><span> Enumerable([iter, v]() mutable
    {
        </span><span>if</span> (iter == v-&gt;end()) <span>return</span> std::make_pair(<span>false</span><span>, T());
        </span><span>return</span> std::make_pair(<span>true</span>, *iter++<span>);
    });
}

private:
ClosureT m_closure;
};

template
auto
from(const ContainerT& c) -> Enumerable<
typename DeclareType
::Type >
{
typedef typename DeclareType
::Type RType;
bool init = false;
auto iter
= std::end(c);
return Enumerable(init, iter, &c mutable
{
if (!init) {
init
= true;
iter
= std::begin(c);
}
if (iter == std::end(c)) return std::make_pair(false, RType());
return std::make_pair(true, *iter++);
});
}

template
auto range(T begin, T end, T step
= 1) -> Enumerable
{
T cur
= begin;
return Enumerable(cur, end, step mutable
{
if ((step > 0 && cur >= end) || (step < 0 && cur <= end)) {
return std::make_pair(false, T());
}
T r
= cur;
cur
+= step;
return std::make_pair(true, r);
});
}

template
auto range(T end)
-> Enumerable
{
return range(T(), end);
}

#endif(*std::begin(c))>(*std::begin(c))></std::vector</std::</std::</std::</std::vector</std::vector</std::vector,></std::map,>,></decltype(f((t)</decltype(f((t)*></std::pair<(*std::begin(c))>

(2) 测试代码main.cpp (比我的代码更烂的是我的英语)

#include "pch.h"

#include "linq.h"

#include 
#include <string>
#include 

template
void printC(const T& v)
{
    for (auto i : v) cout << i << ',';
    cout << endl;
}

template
void print(const T& v)
{
    cout << v << endl;
}

bool startsWith(const std::string& s, const std::string& prefix)
{
    return s.find(prefix) == 0;
}

void featureTest()
{
    // 1. standard
    {
        auto query = range(10)
            .where([](int i){ return i % 2; })
            .select([](int i){ return i + 1; });
        auto ref = {2, 4, 6, 8, 10};
        assert(std::equal(ref.begin(), ref.end(), query.begin()));
    }
    // 2. deferred range
    {
        assert(range(123LL, 1000000000000LL).first() == 123);
    }
    // 3. deferred action
    {
        int selectCnt = 0;

        auto query = range(1, 1000)
            .where([](int i){ return i % 2 == 0; })
            .select([&selectCnt](int i)
                {
                    ++selectCnt;
                    return i;
                })
            .where([](int i) { return i % 4 == 0; })
            .head(2);
        auto query2 = query;

        for (auto i : query) {}
        assert(selectCnt == 4);

        for (auto i : query2) {}
        assert(selectCnt == 8);
    }
    // 4. copy semantic
    {
        auto query = range(10).head(5);
        auto query2 = query;

        auto ref = {0, 1, 2, 3, 4};
        assert(std::equal(ref.begin(), ref.end(), query.begin()));
        assert(std::equal(ref.begin(), ref.end(), query2.begin()));

        auto iter = query.begin();
        ++iter;
        auto iter2 = iter;

        ref = {1, 2, 3, 4};
        assert(std::equal(ref.begin(), ref.end(), iter));
        assert(std::equal(ref.begin(), ref.end(), iter2));
    }
    // 5. always reference the neweast data of dataSource
    {
        std::vector<:>string> dataSrc{"A_abc", "A_def", "B_abc", "B_def"};

        auto query = from(dataSrc)
            .head(3)
            .where([](const std::string& s) { return startsWith(s, "B_"); });

        auto ref = {"B_abc"};
        assert(std::equal(ref.begin(), ref.end(), query.begin()));

        dataSrc.clear();
        dataSrc.shrink_to_fit();
        dataSrc = {"B#_abc", "B_123", "B_1234", "B_321", "B_111"};
        ref = {"B_123", "B_1234"};
        assert(std::equal(ref.begin(), ref.end(), query.begin()));
    }
    // 6. invoke the operator new as least as possible
    {
    }
    // 7. you can use query after the dataSource has been destroyed, by the use of 'reserve'
    {
        Enumerable<int> query;
        {
            std::vector<int> v{1, 2, 3, 4};
            // query = from(v).select([](int i){ return i % 2; });
            query = from(v).reserve().select([](int i){ return i % 2; });

            auto ref = {1, 0, 1, 0};
            assert(std::equal(ref.begin(), ref.end(), query.begin()));
        }

        auto ref = {1, 0, 1, 0};
        assert(std::equal(ref.begin(), ref.end(), query.begin()));
    }
    // 8. add action to an exist query
    {
        auto query = range(10).where([](int i){ return i < 5;});
        auto ref = {0, 1, 2, 3, 4};
        assert(std::equal(ref.begin(), ref.end(), query.begin()));

        auto query2 = query.select([](int i){ return i * i; });
        ref = {0, 1, 4, 9, 16};
        assert(std::equal(ref.begin(), ref.end(), query2.begin()));
    }
}

void functionTest()
{
    // 1. from, select, where, cast
    {
        int a[]{5, 6, 7, 8, 9};
        auto query = from(a)
            .where([](int i){ return i % 3; })
            .select([](int i) { return i * i;});
        auto ref = {25, 49, 64};
        assert(std::equal(ref.begin(), ref.end(), query.begin()));
    }
    // 2. range, all, any
    {
        assert(range(10).all([](int i){ return i >= 0;}));
        assert(!range(10).all([](int i){ return i > 0;}));
        assert(from(std::vector<:>string>{"_a", "b"})
                .any([](const std::string& s){ return startsWith(s, "_"); }));
        assert(!from(std::vector<:>string>{"@a", "b"})
                .any([](const std::string& s){ return startsWith(s, "_"); }));
    }
    // 3. cast, average
    {
        assert(range(1, 5).average() == 2);
        assert(range(1, 5).cast<float>().average() == 2.5);
    }
    // 4. contain, count
    {
        int a[]{1, 2, 1, 1, 3, 2, };
        assert(from(a).contain(3));
        assert(!from(a).contain(4));
        assert(from(a).count(1) == 3);
        assert(from(a).count([](int i) { return i % 2; }) == 4);
    }
    // 5. first, last, head, tail
    {
        int a[]{3, 5, 7, 9, 11};
        assert(from(a).first() == 3);
        assert(from(a).last() == 11);

        auto ref = {3, 5};
        auto query = from(a).head(2);
        assert(std::equal(ref.begin(), ref.end(), query.begin()));

        ref = {7, 9, 11};
        query = from(a).tail(3);
        assert(std::equal(ref.begin(), ref.end(), query.begin()));
    }
    // 6. groupBy
    {
        auto query = range(10).groupBy([](int i) { return i % 3;});
        int refs[][4] = {
            {0, 3, 6, 9},
            {1, 4, 7,},
            {2, 5, 8,},
        };
        int n = 0;
        for (auto i : query) {
            assert(i.first == refs[n][0]);
            assert(std::equal(i.second.begin(), i.second.end(), refs[n]));
            ++n;
        }
        assert(n == 3);
    }
    // 7. takeUntil, skipUntil
    {
        auto query = range(10).takeUntil([](int i){ return i > 5; });
        auto ref = {0, 1, 2, 3, 4, 5};
        assert(std::equal(ref.begin(), ref.end(), query.begin()));

        query = range(10).skipUntil([](int i){ return i > 5; });
        ref = { 6, 7, 8, 9};
        assert(std::equal(ref.begin(), ref.end(), query.begin()));
    }
    // 8. max, min
    {
        int a[]{3, 2, 5, 8, 10, -3};
        assert(from(a).min() == -3);
        assert(from(a).max() == 10);
    }
    // 9. reduce
    {
        assert(range(1, 11).reduce([](int a, int b){ return a + b; }) == 55);
        assert(range(1, 11).reduce([](int a, int b){ return a * b; }, 0) == 0);
        assert(range(1, 11).reduce([](int a, int b){ return a * b; }, 1) == 3628800);
    }
    // 10. unique, sort, random
    {
        int a[]{3, 5, 5, 4, 2, 1, 2};

        auto query = from(a).unique();
        auto ref = {3, 5, 4, 2, 1};
        assert(std::equal(ref.begin(), ref.end(), query.begin()));

        ref = {5, 4, 3, 2, 1};
        query = query.sort().sort([](int a, int b){ return a > b; });
        assert(std::equal(ref.begin(), ref.end(), query.begin()));
        query = query.random();
        assert(!std::equal(ref.begin(), ref.end(), query.begin()));
    }
    // 11. intersect, _union
    {
        int a[]{3, 5, 11};
        auto query = range(10).intersect(from(a));
        auto ref = {3, 5};
        assert(std::equal(ref.begin(), ref.end(), query.begin()));

        ref = {3, 4, 5, 6};
        query = query._union(range(4, 7));
        assert(std::equal(ref.begin(), ref.end(), query.begin()));
    }
}

int main()
{
    featureTest();
    functionTest();
}

为什么不把它提交到git hub之类的专门代码仓库?一则我没有用过,二则,这种代码是我的write-only构想实践码,不提供后续维护的:)

Original: https://www.cnblogs.com/cbscan/archive/2012/10/20/2732773.html
Author: Scan.
Title: [C++]一份Linq to object的C++实现

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/535076/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • C++ std::Recursive_mutex 支持 “对同一互斥量进行嵌套加锁”

    使用场景:一个类的不同成员函数之间,存在相互调用的情况, 如果这样的成员函数作为线程的入口函数时,就会出现在成员函数 func1()中对某个互斥量上锁,并且, func1()中调用…

    C++ 2023年5月29日
    046
  • 聊聊 C++ 中的几种智能指针 (下)

    一:背景 上一篇我们聊到了C++ 的 auto_ptr ,有朋友说已经在 C++ 17 中被弃用了,感谢朋友提醒,今天我们来聊一下 C++ 11 中引入的几个智能指针。 uniqu…

    C++ 2023年5月29日
    055
  • c++ union内存

    看一个例子: 输出结果: 为什么是这样的呢? 因为A是union,所以在内存中存储的格式为: 高地址 ————> 低地址 12…

    C++ 2023年5月29日
    049
  • C++ 知识点

    知识点 说明 所谓的引用就是给变量取一个别名,使一块内存空间可以通过几个变量名来访问。声明引用类型的变量需要在变量名前加上符号&,并且必须指定初值,即被引用的变量。 C++…

    C++ 2023年5月29日
    050
  • QT调用Delphi生成的COM组件(这样MinGW可以调用VC++做的COM了,有利于对接大厂只提供VC++ SDK的情况,也可转换lib)

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    C++ 2023年5月29日
    054
  • c++11 auto 与 decltype 详解

    一. auto简介 编程时候常常需要把表达式的值付给变量,需要在声明变量的时候清楚的知道变量是什么类型。然而做到这一点并非那么容易(特别是模板中),有时候根本做不到。为了解决这个问…

    C++ 2023年5月29日
    063
  • (筆記) 如何讀取binary file某個byte的值? (C/C++) (C)

    Abstract通常公司為了保護其智慧財產權,會自己定義檔案格式,其header區會定義每個byte各代表某項資訊,所以常常需要直接對binary檔的某byte直接進行讀取。 In…

    C++ 2023年5月29日
    053
  • C/C++ 中带空格字符串输入的一些小trick

    今天在重温 C++ 的时候发现自己存在的一些问题,特此记录下来。 我们可以看一下下面这段代码: #include #include #include #include using …

    C++ 2023年5月29日
    052
  • Delphi XE8,C++ Builder XE8,RAD Studio XE8 官方 ISO 文件下载,附激活工具

    RAD Studio XE8 v22.0.19027.8951 官方ISO下载(6.72G):http://altd.embarcadero.com/download/radstu…

    C++ 2023年5月29日
    077
  • 转:TinyXM–优秀的C++ XML解析器

    include include “tinyxml.h” include “tinystr.h” include include in…

    C++ 2023年5月29日
    047
  • C++内存管理

    [ 导语] 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内…

    C++ 2023年5月29日
    048
  • C++11多线程

    在C++11之前,C++语言层面是不支持多线程的,想利用C++实现并发程序,借助操作系统的API实现跨平台的并发程序存在着诸多不便。在C++11中,终于提供了多线程的标准库,提供了…

    C++ 2023年5月29日
    052
  • C/C++中的常量指针与指针常量(转)

    常量指针 常量指针是指向常量的指针,指针指向的内存地址的内容是不可修改的。 常量指针定义”const int p=&a;”告诉编译器,p是常量,不能将*p作…

    C++ 2023年5月29日
    040
  • 34.C++-QT信号槽分析

    moc 元对象编译器, 全称是 Meta-Object Compiler,也就是”元对象编译器”。是QT翻译扩展语法到C++语言的工具,目前见扩展了信号与槽…

    C++ 2023年5月29日
    056
  • Windows 8 添加隐私策略(C++版)

    well.新年上班第一天.不幸收到MS官方针对我们Snack Cards应用程序被打回消息.看看Report 内容如下: The app has declared access t…

    C++ 2023年5月29日
    060
  • [C++] 对象指针使用方法

    对象指针:指向类对象的指针 类指针指向类变量(对象)的地址 对象指针定义格式: 举例: #include using namespace std; class Student { …

    C++ 2023年5月29日
    054
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球