Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions doc/modules/ROOT/examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,37 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_definitions(BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS)
endif()

# Hold the examples to the test warning level, plus -Wextra. There is no
# Jamfile here, so b2 never compiles the examples and this is the only check
# they get. Set before the first target, so the options also reach shared_libs
# and the step-by-step subdirectories.
if (BOOST_OPENMETHOD_WARNINGS_AS_ERRORS)
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC"
OR CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES "MSVC")
add_compile_options(/W4 /WX)
else()
add_compile_options(-Wall -Wextra -Werror)

# friendship.cpp and friendship_across_namespaces.cpp name
# virtual_ptr<Cat> in a friend declaration inside Animal, before Cat is
# defined - which is the point of the example. Defaulting the registry
# argument runs the affinity probe, a SFINAE context, so GCC 16 reports
# that the answer may change once Cat is complete. The library asks the
# question again under its `rechecked` tag, where the class has to be
# complete, and refuses an answer that has changed. -Wsfinae-incomplete
# is on by default - neither -Wall nor -Wextra brings it in - so this
# keeps the diagnostic visible without failing the build. Probed rather
# than tied to a version: only GCC 16 knows the option, and naming it on
# any other compiler is a hard error.
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(
-Wsfinae-incomplete BOOST_OPENMETHOD_HAS_WSFINAE_INCOMPLETE)
if (BOOST_OPENMETHOD_HAS_WSFINAE_INCOMPLETE)
add_compile_options(-Wno-error=sfinae-incomplete)
endif()
endif()
endif()

file(GLOB cpp_files "*.cpp")

foreach (cpp ${cpp_files})
Expand Down
6 changes: 4 additions & 2 deletions doc/modules/ROOT/examples/custom_rtti/1/custom_rtti.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ struct custom_rtti : boost::openmethod::policies::rtti {
if constexpr (is_polymorphic<T>) {
return reinterpret_cast<type_id>(T::static_type);
} else {
return reinterpret_cast<type_id>(0);
static const char id = 0;

return reinterpret_cast<type_id>(&id);
}
}

Expand All @@ -70,7 +72,7 @@ struct custom_rtti : boost::openmethod::policies::rtti {
if constexpr (is_polymorphic<T>) {
return reinterpret_cast<type_id>(obj.type);
} else {
return reinterpret_cast<type_id>(0);
return static_type<T>();
}
}
};
Expand Down
8 changes: 5 additions & 3 deletions doc/modules/ROOT/examples/custom_rtti/2/custom_rtti.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ struct custom_rtti : boost::openmethod::policies::deferred_static_rtti {
if constexpr (is_polymorphic<T>) {
return reinterpret_cast<type_id>(T::static_type);
} else {
return reinterpret_cast<type_id>(0);
static const char id = 0;

return reinterpret_cast<type_id>(&id);
}
}

Expand All @@ -66,7 +68,7 @@ struct custom_rtti : boost::openmethod::policies::deferred_static_rtti {
if constexpr (is_polymorphic<T>) {
return reinterpret_cast<type_id>(obj.type);
} else {
return reinterpret_cast<type_id>(0);
return static_type<T>();
}
}
};
Expand Down Expand Up @@ -113,6 +115,6 @@ int main() {
std::cout << value(e) << "\n"; // 2 3 + 4 * = 20
}

auto call_via_ref(const Node& node, std::ostream& os) {
auto call_via_ref(const Node& node) {
return value(node);
}
4 changes: 4 additions & 0 deletions doc/modules/ROOT/examples/matrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ auto main() -> int {

cout << a << "\n";
cout << b << "\n";
cout << a * b << "\n";
cout << b * b << "\n";
cout << times(s, a.rep()) << "\n";
cout << times(b.rep(), s) << "\n";

return 0;
}
4 changes: 4 additions & 0 deletions doc/modules/ROOT/examples/matrix_intrusive_vptr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ auto main() -> int {

cout << a << "\n";
cout << b << "\n";
cout << a * b << "\n";
cout << b * b << "\n";
cout << times(s, a.rep()) << "\n";
cout << times(b.rep(), s) << "\n";

return 0;
}
12 changes: 6 additions & 6 deletions doc/modules/ROOT/examples/slides.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ namespace typeswitch {
using namespace nodes;

auto to_rpn(const Node& node) -> string {
if (auto expr = dynamic_cast<const Number*>(&node)) {
return to_string(expr->value());
} else if (auto expr = dynamic_cast<const Plus*>(&node)) {
return to_rpn(expr->left) + " " + to_rpn(expr->right) + " +";
} else if (auto expr = dynamic_cast<const Times*>(&node)) {
return to_rpn(expr->left) + " " + to_rpn(expr->right) + " *";
if (auto number = dynamic_cast<const Number*>(&node)) {
return to_string(number->value());
} else if (auto plus = dynamic_cast<const Plus*>(&node)) {
return to_rpn(plus->left) + " " + to_rpn(plus->right) + " +";
} else if (auto times = dynamic_cast<const Times*>(&node)) {
return to_rpn(times->left) + " " + to_rpn(times->right) + " *";
}
throw runtime_error("unknown node type");
}
Expand Down
19 changes: 15 additions & 4 deletions doc/modules/ROOT/pages/custom_rtti.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -116,19 +116,30 @@ not require Node to be polymorphic in the C++ sense. If we remove the virtual
destructor and implement `value` as an open-method as well, the program will
still work.

Note that a non-"polymorphic" type still gets an id of its own - the address of
a function-local static, as in the library's own cpp:policies::static_rtti[].
It is tempting to return a single placeholder for all of them, since they never
take part in dispatch, but `static_type` is also what identifies a *method*: a
`method<...>` specialization is not derived from `Node`, so it takes the
non-"polymorphic" branch. Hand every method the same id and cpp:initialize[]
merges them into one, pools their overriders, and the first call fails as an
ambiguous call. With a single method in the program nothing goes wrong, which
is what makes the mistake easy to ship.

The policy is quite minimal. It does not support virtual inheritance, because it
does not provide a `dynamic_cast_ref` function. It would not produce good error
or trace messages, because it does not provide a `type_name` function. Instead,
it relies on the `type_name` inherited from cpp:rtti::defaults[]. It
renders types as adorned integers, e.g. "type_id(2)". All non-"polymorphic"
types would be rendered the same way, as "type_id(0)".
renders types as adorned integers, e.g. "type_id(2)" for a node, and an
unwieldy address for everything else.

cpp:rtti::defaults[] also provides a default implementation for `type_index`,
which simply returns its argument.

Now we need a policy to get a v-table pointer from an object. Our RTTI system
has an interesting property: its type ids are monotonically allocated in a
small, dense range. It means that we can use them as indexes in a vector.
has an interesting property: the ids it gives to the classes that take part in
dispatch are monotonically allocated in a small, dense range. It means that we
can use them as indexes in a vector.
`vptr_vector` is perfect for that. So here is our registry:

[source,c++]
Expand Down
Loading