mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2025-12-27 10:33:59 -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)
|
// Library code: implementing the metaclass (once)
|
||||||
|
|
||||||
$class interface {
|
consteval void interface(meta::info source) {
|
||||||
constexpr {
|
for (meta::info mem : meta::member_range(source)) {
|
||||||
compiler.require($interface.variables().empty(),
|
meta::compiler.require(!meta::is_data_member(mem), "interfaces may not contain data");
|
||||||
"interfaces may not contain data");
|
meta::compiler.require(!meta::is_copy(mem) && !meta::is_move(mem),
|
||||||
for... (auto f : $interface.functions()) {
|
"interfaces may not copy or move; consider"
|
||||||
compiler.require(!f.is_copy() && !f.is_move(),
|
" a virtual clone() instead");
|
||||||
"interfaces may not copy or move; consider a"
|
|
||||||
" virtual clone() instead");
|
if (meta::has_default_access(mem))
|
||||||
if (!f.has_access()) f.make_public();
|
meta::make_public(mem);
|
||||||
compiler.require(f.is_public(),
|
|
||||||
"interface functions must be public");
|
meta::compiler.require(meta::is_public(mem), "interface functions must be public");
|
||||||
f.make_pure_virtual();
|
|
||||||
}
|
meta::make_pure_virtual(mem);
|
||||||
}
|
|
||||||
virtual ~interface() noexcept { }
|
-> mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
-> fragment struct X { virtual ~X() noexcept {} };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//====================================================================
|
//====================================================================
|
||||||
// User code: using the metaclass to write a type (many times)
|
// User code: using the metaclass to write a type (many times)
|
||||||
|
|
||||||
interface Shape {
|
class(interface) Shape {
|
||||||
int area() const;
|
int area() const;
|
||||||
void scale_by(double factor);
|
void scale_by(double factor);
|
||||||
};
|
};
|
||||||
@@ -37,12 +44,10 @@ interface Shape {
|
|||||||
// Shape(const Shape&); // error: interfaces may not copy or move;
|
// Shape(const Shape&); // error: interfaces may not copy or move;
|
||||||
// // consider a virtual clone() instead
|
// // consider a virtual clone() instead
|
||||||
|
|
||||||
// Godbolt.org note: Click the "triangle ! icon" to see the output
|
consteval {
|
||||||
constexpr {
|
meta::compiler.print(reflexpr(Shape));
|
||||||
compiler.debug($Shape);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//====================================================================
|
//====================================================================
|
||||||
// And then continue to use it as "just a class" as always... this is
|
// 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
|
// normal code just as if we'd written Shape not using a metaclass
|
||||||
@@ -53,6 +58,10 @@ public:
|
|||||||
void scale_by(double factor) override { }
|
void scale_by(double factor) override { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
consteval {
|
||||||
|
meta::compiler.print(reflexpr(Circle));
|
||||||
|
}
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
int main() {
|
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 @@
|
|||||||
//====================================================================
|
// Pick an appropriate example from the Load/Save
|
||||||
// Library code: implementing the metaclass (once)
|
// icon above.
|
||||||
|
|
||||||
$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);
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user