mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2025-12-27 07:04:04 -05:00
Partially address #2201
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
virtual ~interface() noexcept { }
|
||||
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;
|
||||
}
|
||||
|
||||
-> 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() {
|
||||
|
||||
61
examples/cppx/Interface_(CppCon_2017).cpp
Normal file
61
examples/cppx/Interface_(CppCon_2017).cpp
Normal 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();
|
||||
}
|
||||
47
examples/cppx/Value_(CppCon_2017).cpp
Normal file
47
examples/cppx/Value_(CppCon_2017).cpp
Normal 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);
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user