Date: Thu, 10 Jun 2021 18:41:43 +0300
Hi.
I’ve been playing around implementing a feature similar to python
decorators using the reflection implementation in
https://github.com/lock3/meta, based on the [P1240](https://wg21.link/P1240]
syntax.
Currently I’ve managed to compile the following code on my branch:
#include <experimental/compiler>
#include <experimental/meta>
#include <iostream>
#include <utility>
#define FWD(x) std::forward<decltype(x)>(x)
namespace meta = std::experimental::meta;
using string_type = const char*;
constexpr bool string_eq(string_type s1, string_type s2) {
while (*s1 != '\0' && *s1 == *s2) {
s1++;
s2++;
}
return *s1 == *s2;
}
consteval void decorate(meta::info source) {
for (auto mem : meta::members_of(source)) {
if (meta::has_attribute(mem, "decorator")) {
if (not meta::is_function(mem)) {
meta::compiler.error("can only decorate functions");
}
for (const auto attribute : meta::attributes_of(mem)) {
if (string_eq(meta::name_of(attribute), "decorator")) {
for (const auto decorator : meta::attribute_arguments_of(attribute)) {
->fragment struct {
template <typename... Args>
static auto unqualid(% {mem})(Args&&... args) {
return idexpr(% {decorator})(idexpr(% {mem}))(FWD(args)...);
}
};
}
meta::set_new_name(mem, __concatenate("orig_", meta::name_of(mem)));
->mem;
}
}
}
}
}
template <typename F>
auto logger(F&& f) {
return [f]<typename... Args>(Args && ... args) {
std::cout << "calling " << meta::name_of(reflexpr(f));
std::cout << "(";
(void)(std::cout << ... << args);
std::cout << ")\n";
return f(FWD(args)...);
};
}
struct(decorate) Foo{
[[decorator(logger)]] static void fn(int){}
};
int main() {
meta::compiler.print(reflexpr(Foo));
Foo::fn(42);
}
with this output (from a local compiler explorer I run)
ASM generation compiler returned: 0
struct Foo {
template <typename ...Args> static auto fn(Args &&...args) {
return logger(fn)(std::forward<decltype(args)>(args)...);
}
static void orig_fn(int) {
}
};
Execution build compiler returned: 0
Program returned: 0
calling f(42)
For this to work I had to tell clang not to remove unknown attributes as
well as add some attribute reflection functions to meta.
Do you think this is a valuable usage?
Do you think attribute reflection functions should be added to the standard
meta library?
Best regards,
Dvir
I’ve been playing around implementing a feature similar to python
decorators using the reflection implementation in
https://github.com/lock3/meta, based on the [P1240](https://wg21.link/P1240]
syntax.
Currently I’ve managed to compile the following code on my branch:
#include <experimental/compiler>
#include <experimental/meta>
#include <iostream>
#include <utility>
#define FWD(x) std::forward<decltype(x)>(x)
namespace meta = std::experimental::meta;
using string_type = const char*;
constexpr bool string_eq(string_type s1, string_type s2) {
while (*s1 != '\0' && *s1 == *s2) {
s1++;
s2++;
}
return *s1 == *s2;
}
consteval void decorate(meta::info source) {
for (auto mem : meta::members_of(source)) {
if (meta::has_attribute(mem, "decorator")) {
if (not meta::is_function(mem)) {
meta::compiler.error("can only decorate functions");
}
for (const auto attribute : meta::attributes_of(mem)) {
if (string_eq(meta::name_of(attribute), "decorator")) {
for (const auto decorator : meta::attribute_arguments_of(attribute)) {
->fragment struct {
template <typename... Args>
static auto unqualid(% {mem})(Args&&... args) {
return idexpr(% {decorator})(idexpr(% {mem}))(FWD(args)...);
}
};
}
meta::set_new_name(mem, __concatenate("orig_", meta::name_of(mem)));
->mem;
}
}
}
}
}
template <typename F>
auto logger(F&& f) {
return [f]<typename... Args>(Args && ... args) {
std::cout << "calling " << meta::name_of(reflexpr(f));
std::cout << "(";
(void)(std::cout << ... << args);
std::cout << ")\n";
return f(FWD(args)...);
};
}
struct(decorate) Foo{
[[decorator(logger)]] static void fn(int){}
};
int main() {
meta::compiler.print(reflexpr(Foo));
Foo::fn(42);
}
with this output (from a local compiler explorer I run)
ASM generation compiler returned: 0
struct Foo {
template <typename ...Args> static auto fn(Args &&...args) {
return logger(fn)(std::forward<decltype(args)>(args)...);
}
static void orig_fn(int) {
}
};
Execution build compiler returned: 0
Program returned: 0
calling f(42)
For this to work I had to tell clang not to remove unknown attributes as
well as add some attribute reflection functions to meta.
Do you think this is a valuable usage?
Do you think attribute reflection functions should be added to the standard
meta library?
Best regards,
Dvir
Received on 2021-06-10 10:41:59