Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

C++ Extension with Mixin

This simple header-only library add useful functions in STL.

vector<int> a{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto b = a.filter([](auto &value) {
    return value % 2 == 0;
}).map([](auto &value) {
    return value * 10;
}).for_each_indexed([&b](auto idx, auto &value) {
    cout << value << (idx < b.size() - 1 ? ", " : "");
});

All things happen at compile time and you can get IDE auto-complete when writing above codes.

Motivation

If you know JavaScript or Kotlin, you might have written something like this:

myIterable.forEach((val) => { // do something })

const x = myIterable.map((val) => { // do something })

Or some chained calls:

myIterable.filter((val) => {
  // ...
}).map((val) => {
  // ...
}).forEach((val) => {
  // ...
})

But when it comes to C++, things are not so easy. You, as a C++ rising star, may know you can do similar iterations by #include<algorithm>.

But there are no chained calls!

Inspired by Kotlin extension functions and the github repo libciabatta, we can also add "extension functions" to STL containers by mixin.

Usage

Add Extensions To An Existing Object

using Mixin::mix;
using IterablePatch::ForEachIndexed, IterablePatch::Map, IterablePatch::Filter;
using std::cout, std::endl;

struct ObjStyleTest {
    static void run() {
        cout << "Object style syntax: mix things into an object." << endl;
        std::vector<int> a{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        auto b = mix<ForEachIndexed, Map, Filter>::in(a);
        auto c = b.filter([](auto &value) {
            return value % 2 == 0;
        }).map([](auto &value) {
            return value * 10;
        });
        c.for_each_indexed([&c](auto idx, auto &n) {
            cout << n << (idx < c.size() - 1 ? ", " : "");
        });
        cout << endl;

        // Yes, it can be automatically cast back!
        std::vector<int> d = c;
        cout << "Testing implicit cast" << endl;
        bool flag = true;
        c.for_each_indexed([&flag, &d](auto idx, auto &v) {
            flag &= v == d[idx];
        });
        cout << (flag ? "YES!" : "NO!") << endl << endl;
    }
};

Create A Type Alias And Use It To Create Objects

struct ClassStyleTest {
    template<typename T>
    using vector = typename mix<ForEachIndexed, Map, Filter>::in_class<std::vector<T>>;

    static void run() {
        cout << "Class style syntax: mix things into a class" << endl;
        // Normal constructors and list initializer are all supported.
        // vector<int> a(3, 10);
        // vector<int> a(2);
        vector<int> a{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        auto b = a.filter([](auto &value) {
            return value % 2 == 0;
        }).map([](auto &value) {
            return value * 10;
        });
        b.for_each_indexed([&b](auto idx, auto &value) {
            cout << value << (idx < b.size() - 1 ? ", " : "");
        });
        cout << endl;
        // Yes, it can be automatically cast back!
        std::vector<int> c = b;
        cout << "Testing implicit cast" << endl;
        bool flag = true;
        b.for_each_indexed([&b, &flag](auto idx, auto &value) {
            flag &= value == b[idx];
        });
        cout << (flag ? "YES!" : "NO!") << endl << endl;
    }
};

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages