|
34 | 34 |
|
35 | 35 | namespace boost::openmethod { |
36 | 36 |
|
37 | | -//! N2216 ambiguity resolution. |
38 | | -//! |
39 | | -//! If `n2216` is present in @ref initialize\'s `Options`, additional steps are |
40 | | -//! taken to select a single overrider in presence of ambiguous overriders sets, |
41 | | -//! according to the rules defined in the N2216 paper. If the normal resolution |
42 | | -//! procedure fails to select a single overrider, the following steps are |
43 | | -//! applied, in order: |
44 | | -//! |
45 | | -//! - If the return types of the remaining overriders are all polymorphic and |
46 | | -//! covariant, and one of the return types is more specialized thjat all the |
47 | | -//! others, use it. |
48 | | -//! |
49 | | -//! - Otherwise, pick one of the overriders. Which one is used is unspecified, |
50 | | -//! but remains the same throughtout the program, and across different runs of |
51 | | -//! the same program. |
52 | | -struct n2216; |
53 | | - |
54 | 37 | namespace detail { |
55 | 38 |
|
56 | 39 | template<class Reports, class Facets, typename = void> |
@@ -260,8 +243,27 @@ auto operator<<(trace_type<Registry>& trace, const spec_name& sn) |
260 | 243 | return trace; |
261 | 244 | } |
262 | 245 |
|
| 246 | +struct option_base {}; |
| 247 | + |
263 | 248 | } // namespace detail |
264 | 249 |
|
| 250 | +//! N2216 ambiguity resolution. |
| 251 | +//! |
| 252 | +//! If `n2216` is present in @ref initialize\'s `Options`, additional steps are |
| 253 | +//! taken to select a single overrider in presence of ambiguous overriders sets, |
| 254 | +//! according to the rules defined in the N2216 paper. If the normal resolution |
| 255 | +//! procedure fails to select a single overrider, the following steps are |
| 256 | +//! applied, in order: |
| 257 | +//! |
| 258 | +//! - If the return types of the remaining overriders are all polymorphic and |
| 259 | +//! covariant, and one of the return types is more specialized thjat all the |
| 260 | +//! others, use it. |
| 261 | +//! |
| 262 | +//! - Otherwise, pick one of the overriders. Which one is used is unspecified, |
| 263 | +//! but remains the same throughtout the program, and across different runs of |
| 264 | +//! the same program. |
| 265 | +struct n2216 : detail::option_base {}; |
| 266 | + |
265 | 267 | // Definition of the nested template struct outside the registry class |
266 | 268 | template<class... Policies> |
267 | 269 | template<class... Options> |
@@ -1375,26 +1377,62 @@ void registry<Policies...>::compiler<Options...>::print( |
1375 | 1377 | << " ambiguous\n"; |
1376 | 1378 | } |
1377 | 1379 |
|
1378 | | -template<class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY, class... Options> |
1379 | | -auto initialize() { |
1380 | | - if (odr_check<Registry>::count > 1) { |
1381 | | - // Multiple definitions of default_registry detected. |
1382 | | - // This indicates an ODR violation. |
1383 | | - // Signal a final_error using the error handler, then abort. |
1384 | | - if constexpr (Registry::has_error_handler) { |
1385 | | - Registry::error_handler::error(odr_violation()); |
| 1380 | +namespace detail { |
| 1381 | +template<typename T, class... Options> |
| 1382 | +struct initialize_aux |
| 1383 | + : initialize_aux<T, BOOST_OPENMETHOD_DEFAULT_REGISTRY, Options...> {}; |
| 1384 | + |
| 1385 | +template<class Registry, class... Options> |
| 1386 | +struct initialize_aux< |
| 1387 | + std::void_t<typename Registry::registry_type>, Registry, Options...> { |
| 1388 | + static_assert( |
| 1389 | + (std::is_base_of_v<detail::option_base, Options> && ...), |
| 1390 | + "invalid option type"); |
| 1391 | + static auto fn() { |
| 1392 | + if (odr_check<Registry>::count > 1) { |
| 1393 | + // Multiple definitions of default_registry detected. |
| 1394 | + // This indicates an ODR violation. |
| 1395 | + // Signal a final_error using the error handler, then abort. |
| 1396 | + if constexpr (Registry::has_error_handler) { |
| 1397 | + Registry::error_handler::error(odr_violation()); |
| 1398 | + } |
| 1399 | + |
| 1400 | + std::abort(); |
1386 | 1401 | } |
1387 | 1402 |
|
1388 | | - std::abort(); |
1389 | | - } |
| 1403 | + typename Registry::template compiler<Options...> comp; |
| 1404 | + comp.initialize(); |
1390 | 1405 |
|
1391 | | - typename Registry::template compiler<Options...> comp; |
1392 | | - comp.initialize(); |
| 1406 | + return comp; |
| 1407 | + } |
| 1408 | +}; |
| 1409 | +} // namespace detail |
1393 | 1410 |
|
1394 | | - return comp; |
| 1411 | +//! Initialize a registry. |
| 1412 | +//! |
| 1413 | +//! `initialize` must be called, typically at the beginning of `main`, before |
| 1414 | +//! using any of the methods in a registry. It sets up the v-tables, |
| 1415 | +//! multi-method dispatch tables, and any other data required by the policies. |
| 1416 | +//! |
| 1417 | +//! If the first template argument is a registry, initialize it. Otherwise, |
| 1418 | +//! initialize the default registry. Additional template arguments, if any, must |
| 1419 | +//! be option types (@ref n2216 or @ref enable_trace). |
| 1420 | +//! |
| 1421 | +//! @note |
| 1422 | +//! A translation unit that contains a call to `initialize` must include the |
| 1423 | +//! `<boost/openmethod/initialize.hpp>` header. |
| 1424 | +//! |
| 1425 | +//! @par Errors |
| 1426 | +//! |
| 1427 | +//! @li @ref missing_class: A class used in a virtual parameter was |
| 1428 | +//! not registered. |
| 1429 | +//! |
| 1430 | +//! @li Errors reported by the policies. |
| 1431 | +template<class... T> |
| 1432 | +inline auto initialize() { |
| 1433 | + return detail::initialize_aux<void, T...>::fn(); |
1395 | 1434 | } |
1396 | 1435 |
|
1397 | | - |
1398 | 1436 | namespace detail { |
1399 | 1437 |
|
1400 | 1438 | template<class Policy, typename = void> |
|
0 commit comments