[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# vs C++ 全局照明渲染性能比试

    512×512像素,每像素1000采样,C#版本渲染时间为40分47秒 最近有多篇讨论程序语言趋势的博文,其中谈及到C#的性能问题。本人之前未做过相关测试,自己的回覆流于…

    C++ 2023年5月29日
    0107
  • C#与C++之间类型的对应

    Windows Data Type .NET Data Type BOOL, BOOLEAN Boolean or Int32 BSTR String BYTE Byte CHAR…

    C++ 2023年5月29日
    091
  • 聊聊 C++ 大一统的初始化运算符 {}

    一:背景 最近发现 C++ 中的类型初始化操作,没有 {} 运算符搞不定的,蛮有意思,今天我们就来逐一列一下各自的用法以及汇编展现,本来想分为 &#x503C;&#…

    C++ 2023年5月29日
    033
  • Mac eclipse 编译、调试c++ 程序

    可以先安装个CDT插件: eclipse菜单 -> Help -> Install New Software… -> Work with (Add…..

    C++ 2023年5月29日
    065
  • C++入门–友元、静态成员、单例设计模式、成员变量和函数的存储(三)

    posted @2021-12-15 17:06 sgggr 阅读(32 ) 评论() 编辑 Original: https://www.cnblogs.com/sggggr/p/…

    C++ 2023年5月29日
    070
  • C++ mutable的用法

    mutalbe的中文意思是”可变的,易变的”,跟constant(既C++中的const)是反义词。 在C++中,mutable也是为了突破const的限制…

    C++ 2023年5月29日
    058
  • vs不同版本支持的c++版本和PlatformToolset,及在vs中切换c++版本

    找c++资料从网上找确实更快速,但要想深入地理解vc++建议看msdn文档。 vs不同版本支持的c++版本 C++17:vs2017基本支持,vs2015部分支持。C++14:vs…

    C++ 2023年5月29日
    089
  • C++11 并发指南系列

    本系列文章主要介绍 C++11 并发编程,计划分为 9 章介绍 C++11 的并发和多线程编程,分别如下: C++11 并发指南三(std::mutex 详解)(本章计划 1-2 …

    C++ 2023年5月29日
    068
  • C++ 相关库

    C++ 相关库 说明 RapidJSONhttps://github.com/Tencent/rapidjson Original: https://www.cnblogs.com…

    C++ 2023年5月29日
    076
  • C++ 创建静态链接库和动态链接库

    上篇文章演示了如恶化使用C++ 编译的静态链接库和动态链接库,本篇文章主要介绍如何创建静态链接库和动态链接库,本文使用的工具是visual studio 2019 企业版,需要安装…

    C++ 2023年5月29日
    070
  • (筆記) 常用設定暫存器值的編程技巧 (SOC) (C/C++) (C) (Verilog)

    Abstract設定暫存器值是寫firmware時最常見的控制,本文歸納出C語言在寫firmware時常見的編程技巧,並與Verilog相互對照。 Introduction本文將討…

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

    一:背景 我们知道 C++ 是手工管理内存的分配和释放,对应的操作符就是 new/delete 和 new[] / delete[], 这给了程序员极大的自由度也给了我们极高的门槛…

    C++ 2023年5月29日
    095
  • C++ 中 malloc/free与 new/delete区别

    new/delete 通常来说是操作符,就是”+”,”-“一样,malloc/free 是 C++/C 语言的标准库函数 —— 本质…

    C++ 2023年5月29日
    077
  • [C++] 构造函数初始化列表

    C++ 类中构造函数中成员变量的初始化方式有两种: 1、构造函数体内(常用方式) 2、构造函数初始化列表 这两种方式,对于基本类型成员没有区别,但是对复杂类型成员(比如类,结构体等…

    C++ 2023年5月29日
    064
  • Dev-C++

    官网: http://orwelldevcpp.blogspot.com/ 最新版本: Version 5.11 – 27 April 2015 下载链接: https…

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

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

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