Partially address #2201

This commit is contained in:
Matt Godbolt
2020-09-17 21:59:34 -05:00
parent 8c06f7ebfa
commit 33bb9965cd
4 changed files with 139 additions and 67 deletions

View File

@@ -1,29 +1,36 @@
#include <experimental/meta>
#include <experimental/compiler>
using namespace std::experimental;
//====================================================================
// Library code: implementing the metaclass (once)
$class interface {
constexpr {
compiler.require($interface.variables().empty(),
"interfaces may not contain data");
for... (auto f : $interface.functions()) {
compiler.require(!f.is_copy() && !f.is_move(),
"interfaces may not copy or move; consider a"
" virtual clone() instead");
if (!f.has_access()) f.make_public();
compiler.require(f.is_public(),
"interface functions must be public");
f.make_pure_virtual();
consteval void interface(meta::info source) {
for (meta::info mem : meta::member_range(source)) {
meta::compiler.require(!meta::is_data_member(mem), "interfaces may not contain data");
meta::compiler.require(!meta::is_copy(mem) && !meta::is_move(mem),
"interfaces may not copy or move; consider"
" a virtual clone() instead");
if (meta::has_default_access(mem))
meta::make_public(mem);
meta::compiler.require(meta::is_public(mem), "interface functions must be public");
meta::make_pure_virtual(mem);
-> mem;
}
}
virtual ~interface() noexcept { }
-> fragment struct X { virtual ~X() noexcept {} };
};
//====================================================================
// User code: using the metaclass to write a type (many times)
interface Shape {
class(interface) Shape {
int area() const;
void scale_by(double factor);
};
@@ -37,12 +44,10 @@ interface Shape {
// Shape(const Shape&); // error: interfaces may not copy or move;
// // consider a virtual clone() instead
// Godbolt.org note: Click the "triangle ! icon" to see the output
constexpr {
compiler.debug($Shape);
consteval {
meta::compiler.print(reflexpr(Shape));
}
//====================================================================
// And then continue to use it as "just a class" as always... this is
// normal code just as if we'd written Shape not using a metaclass
@@ -53,6 +58,10 @@ public:
void scale_by(double factor) override { }
};
consteval {
meta::compiler.print(reflexpr(Circle));
}
#include <memory>
int main() {

View File

@@ -0,0 +1,61 @@
//====================================================================
// Library code: implementing the metaclass (once)
$class interface {
constexpr {
compiler.require($interface.variables().empty(),
"interfaces may not contain data");
for... (auto f : $interface.functions()) {
compiler.require(!f.is_copy() && !f.is_move(),
"interfaces may not copy or move; consider a"
" virtual clone() instead");
if (!f.has_access()) f.make_public();
compiler.require(f.is_public(),
"interface functions must be public");
f.make_pure_virtual();
}
}
virtual ~interface() noexcept { }
};
//====================================================================
// User code: using the metaclass to write a type (many times)
interface Shape {
int area() const;
void scale_by(double factor);
};
// try putting any of these lines into Shape to see "interface" rules
// enforced => using the metaclass name to declare intent makes
// this code more robust to such changes under maintenance
//
// int i; // error: interfaces may not contain data
// private: void g(); // error: interface functions must be public
// Shape(const Shape&); // error: interfaces may not copy or move;
// // consider a virtual clone() instead
// Godbolt.org note: Click the "triangle ! icon" to see the output
constexpr {
compiler.debug($Shape);
}
//====================================================================
// And then continue to use it as "just a class" as always... this is
// normal code just as if we'd written Shape not using a metaclass
class Circle : public Shape {
public:
int area() const override { return 1; }
void scale_by(double factor) override { }
};
#include <memory>
int main() {
std::unique_ptr<Shape> shape = std::make_unique<Circle>();
shape->area();
}

View File

@@ -0,0 +1,47 @@
//====================================================================
// Library code: implementing the metaclass (once)
$class basic_value {
basic_value() = default;
basic_value(const basic_value& that) = default;
basic_value(basic_value&& that) = default;
basic_value& operator=(const basic_value& that) = default;
basic_value& operator=(basic_value&& that) = default;
constexpr {
for... (auto f : $basic_value.variables())
if (!f.has_access()) f.make_private();
for... (auto f : $basic_value.functions()) {
if (!f.has_access()) f.make_public();
compiler.require(!f.is_protected(), "a value type may not have a protected function");
compiler.require(!f.is_virtual(), "a value type may not have a virtual function");
compiler.require(!f.is_destructor() || f.is_public(), "a value destructor must be public");
}
}
};
$class value : basic_value { };
//====================================================================
// User code: using the metaclass to write a type (many times)
value Point {
int x = 0, y = 0;
Point(int xx, int yy) : x{xx}, y{yy} { }
};
Point get_some_point() { return {1,1}; }
int main() {
Point p1(50,100), p2;
p2 = get_some_point();
p2.x = 42;
}
// Compiler Explorer note: Click the "triangle ! icon" to see the output:
constexpr {
compiler.debug($Point);
}

View File

@@ -1,47 +1,2 @@
//====================================================================
// Library code: implementing the metaclass (once)
$class basic_value {
basic_value() = default;
basic_value(const basic_value& that) = default;
basic_value(basic_value&& that) = default;
basic_value& operator=(const basic_value& that) = default;
basic_value& operator=(basic_value&& that) = default;
constexpr {
for... (auto f : $basic_value.variables())
if (!f.has_access()) f.make_private();
for... (auto f : $basic_value.functions()) {
if (!f.has_access()) f.make_public();
compiler.require(!f.is_protected(), "a value type may not have a protected function");
compiler.require(!f.is_virtual(), "a value type may not have a virtual function");
compiler.require(!f.is_destructor() || f.is_public(), "a value destructor must be public");
}
}
};
$class value : basic_value { };
//====================================================================
// User code: using the metaclass to write a type (many times)
value Point {
int x = 0, y = 0;
Point(int xx, int yy) : x{xx}, y{yy} { }
};
Point get_some_point() { return {1,1}; }
int main() {
Point p1(50,100), p2;
p2 = get_some_point();
p2.x = 42;
}
// Compiler Explorer note: Click the "triangle ! icon" to see the output:
constexpr {
compiler.debug($Point);
}
// Pick an appropriate example from the Load/Save
// icon above.