Last active
October 21, 2016 00:30
-
-
Save SeijiEmery/115f57ad45b5cf579e8078382f6c9d9b to your computer and use it in GitHub Desktop.
metacpp (concept for a c++ preprocessor that adds D-like features to the language)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
meta-cpp: a custom c++ preprocessor that adds D-like features to c++11/c++14. | |
Nicer syntax: | |
class Foo { ... } => class Foo { ... }; | |
interface Foo { void bar(); } => class Foo { virtual void bar() = 0; }; | |
class Foo { this () { ... } } => class Foo { Foo () { ... } }; | |
class Foo { => class Foo { | |
this () : this(0) {} => Foo () : Foo(0) {} | |
this (int bar) { ... } => Foo (int bar) { ... } | |
} => }; | |
class Foo : Bar { => class Foo : Bar { | |
this (int x) : Bar(x) { => Foo (int x) : Bar(x) { | |
... => ... | |
} => } | |
} => } | |
class Foo { | |
int x,y,z; | |
this (this.x, &this.y, int a, int b) : z(a * b) {} | |
} | |
=> => => => => => => => => => => => => => => => => => | |
class Foo { | |
int x, y, z; | |
this (typeof(x) x, &typeof(y) y, int a, int b) : | |
x(x), y(y), z(a + b) {} | |
} | |
Metaprogramming: D-style classinfo. Use either c++ RTTI (?) or roll own typeinfo implementation. | |
struct Foo { | |
int x, y; | |
std::vector<Bar> baz; | |
void pushBar (const Bar& bar) { | |
baz.push_back(bar); | |
} | |
@enable_cttypeinfo(true) | |
} | |
=> => => => => => => => => => => => => => => | |
struct Foo { | |
int x, y; | |
std::vector<Bar> baz; | |
void pushBar (const Bar& bar) { | |
baz.push_back(bar); | |
} | |
struct classinfo { | |
constexpr memberinfo_t[3] members = { | |
{ "x", typeinfo<typeof(x)>::value }, | |
{ "y", typeinfo<typeof(y)>::value }, | |
{ "baz", typeinfo<typeof(baz)>::value }, | |
}; | |
constexpr methodinfo_t[1] methods = { | |
{ "pushBar", &Foo::pushBar, { { "bar", typeinfo<const Bar&>::value }, }, typeinfo::void_ }, | |
}; | |
} | |
} | |
Modules: | |
@module myproject.some_namespace.foo; | |
@import myproject.some_namespace.bar: Foo, Baz; | |
... | |
=> => => => => => => => => => => => => => | |
#ifndef __myproject__some_namespace__foo__ | |
#define __myproject__some_namespace__foo__ | |
#import "some/path/to/my/file.hpp" | |
namespace myproject { | |
namespace some_namespace { | |
namespace foo { | |
using bar::Foo; | |
using bar::Baz; | |
... | |
}; | |
}; | |
}; | |
#endif // __myproject__some_namespace__foo__ | |
Actually scratch that, here's how modules should _actually_ work: | |
myprojpath/src/things/foo.metacpp | |
@module myproj.things.foo; | |
@import stdlib.memory: shared_ptr; | |
class Foo { | |
this (...) { ... } | |
static auto create (...) { | |
return std::make_shared<Foo>(...); | |
} | |
void doFoo () { | |
... | |
} | |
} | |
void barify (Foo& foob) { | |
... | |
} | |
void bazify (Foo foo) { | |
... | |
} | |
myprojpath/src/otherthings/bar.metacpp | |
@module myproj.otherthings.bar; | |
@import myproj.things: Foo, barify; | |
void doStuffWithFoo (Foo& foo) { | |
barify(foo); | |
} | |
void doOtherStuff (...) { | |
auto foo = Foo::create(...); | |
... | |
return foo; | |
} | |
=> => => => => => => => => => => => => => => => => => => => => | |
myprojpath/include/things/foo.hpp | |
#ifndef __generated_headers__myproj_things_foo_hpp__ | |
#define __generated_headers__myproj_things_foo_hpp__ | |
#ifndef __included_cpp_extfile__memory_h__ | |
#define __included_cpp_extfile__memory_h__ | |
#include <memory> | |
#endif | |
class Foo { | |
Foo (...); | |
static std::shared_ptr<Foo> create (...); | |
void doFoo (); | |
} | |
void barify (Foo& foob); | |
void bazify (Foo foo); | |
#endif //__generated_headers__myproj_things_foo_hpp__ | |
myprojpath/src/things/foo.cpp | |
// Adding an extra include guard could actually improve compile speeds, since the c preprocessor | |
// is required to rescan all included header files (can't cache) iirc. | |
#ifndef __generated_headers__myproj_things_foo_hpp__ | |
#include "../../include/things/foo.hpp" | |
#endif | |
class Foo { | |
Foo (...) { | |
... | |
} | |
static std::shared_ptr<Foo> create (...) { | |
return std::make_shared<Foo>(...); | |
} | |
void doFoo () { | |
... | |
} | |
} | |
void barify (Foo& foob) { | |
... | |
} | |
void bazify (Foo foo) { | |
... | |
} | |
myprojpath/include/otherthings/bar.hpp | |
#ifndef __generated_headers__myproj_otherthings_bar_hpp__ | |
#define __generated_headers__myproj_otherthings_bar_hpp__ | |
#ifndef __included_cpp_extfile__memory_h__ | |
#define __included_cpp_extfile__memory_h__ | |
#include <memory> | |
#endif | |
// Note that we're _not_ including foo.hpp; instead, we could | |
// (theoretically) just predeclare the needed classes + types for | |
// our interface _here_, assuming that we don't try to access value types | |
// (and detecting + handling that (eg. shared_ptr<Foo>) would be possible, | |
// just maybe slightly tricky...) | |
// | |
// We could however probably write some custom wrappers for the stdlib | |
// and any used libraries, so instead of writing a really intelligent | |
// parser we could maybe cheat a little, write a smart _enough_ parser, | |
// and explicitely add our own edge cases (ie. we could write a stdlib.memory | |
// file, and write out our cases for what needs to be generated when we | |
// include it in context X, Y, and Z). | |
class Foo; | |
void doStuffWithFoo(Foo& foo); | |
std::shared_ptr<Foo> doOtherStuff (...); | |
#endif //__generated_headers__myproj_otherthings_bar_hpp__ | |
myprojpath/src/otherthings/bar.cpp | |
#ifndef __generated_headers__myproj_otherthings_bar_hpp__ | |
#include "../../include/otherthings/bar.hpp" | |
#endif | |
class Foo { | |
static std::shared_ptr<Foo> create(...); | |
void doFoo (); | |
} | |
void barify (Foo& foob); | |
void doStuffWithFoo (Foo& foo) { | |
barify(foo); | |
} | |
auto doOtherStuff (...) { | |
auto foo = Foo::create(...); | |
... | |
return foo; | |
} | |
Single .metacpp files (akin to .d files); autogenerated .cpp + .hpp files w/ customizable semantics | |
(header only, header + cpp, wrap certain classes in PIMPL, etc). | |
Maybe this is a bit of a pipe dream (don't have specifics on how this would be implemented), | |
but would be super awesome if this were possible (_espescially_ autogenerating metaclass information, | |
autogenerating PIMPL wrappers, merging all files in a certain module into a single .cpp file and | |
automatically partitioning a project into multiple static libs for faster compilation, etc). | |
I would happily move back to c++ if I had a preprocessor powerful enough to do this | |
(and which could be further extended as needed). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment