diff --git a/docs/cpp2/metafunctions.md b/docs/cpp2/metafunctions.md index 7407794d2..edf52cc43 100644 --- a/docs/cpp2/metafunctions.md +++ b/docs/cpp2/metafunctions.md @@ -13,7 +13,7 @@ The most important thing about metafunctions is that they are not hardwired lang ## Applying metafunctions -Metafunctions provide an easy way for a type author to opt into a group of defaults, constraints, and generated functions: Just write `@name` afer the `:` of a declaration, where `name` is the name of the metafunctions. This lets the type author declare (and the human reader see) the intent up front: "This isn't just any `type`, this is a `@value type`" which automatically gives the type default/copy/move construction and assignment, `<=>` with `std::strong_ordering` comparisons, and guarantees that it has a public destructor and no protected or virtual functions: +Metafunctions provide an easy way for a type author to opt into a group of defaults, constraints, and generated functions: Just write `@name` afer the `:` of a declaration, where `name` is the name of the metafunction. This lets the type author declare (and the human reader see) the intent up front: "This isn't just any `type`, this is a `@value type`" which automatically gives the type default/copy/move construction and assignment, `<=>` with `std::strong_ordering` comparisons, and guarantees that it has a public destructor and no protected or virtual functions: ``` cpp title="Example: Using the value metafunction when writing a type" point2d: @value type = { @@ -95,7 +95,7 @@ skat_game: @enum type = { Consider `hearts`: It's a member object declaration, but it doesn't have a type (or a default value) which is normally illegal, but here it's okay because the `@enum` metafunction fills them in: It iterates over all the data members and gives each one the underlying type (here explicitly specified as `i16`, otherwise it would be computed as the smallest signed type that's big enough), and an initializer (by default one higher than the previous enumerator). -Unlike C `enum`, this `@enum` is scoped and strongly typed (does not implicitly convert to the underlying type. +Unlike C `enum`, this `@enum` is scoped and strongly typed (does not implicitly convert to the underlying type.) Unlike C++11 `enum class`, it's "just a `type`" which means it can naturally also have member functions and other things that a type can have: @@ -141,7 +141,8 @@ file_attributes: @flag_enum type = { // name_or_number is declaratively a safe union/variant type: // it has a discriminant that enforces only one alternative // can be active at a time, members always have a name, and -// each member has .is_member() and .member() accessors... +// each member has .is_member() .set_member() and .member() +// accessors using the member name... // the word "union" carries all that meaning as a convenient // and readable opt-in without hardwiring "union" specially // into the language @@ -155,7 +156,9 @@ main: () = { x: name_or_number = (); x.set_name("xyzzy"); // now x is a string - std::cout << x.name(); // prints the string + if x.is_name() { + std::cout << x.name(); // prints the string + } // trying to use x.num() here would cause a Type safety // contract violation, because x is currently a string