Commit 5c35c182f634d61710661e3ee5a3c5bc1b62c915
Committed by
GitHub
1 parent
611431ce
Use e.get_name instead of dynamic_cast (#467)
* Use e.get_name instead of dynamic_cast Also use std::static_pointer_cast instead of std::dynamic_pointer_cast Fixes #466 * feat: Allow RTTI to be turned off * ci: Fix CXX flags * doc: Adding update to book Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com>
Showing
4 changed files
with
19 additions
and
10 deletions
azure-pipelines.yml
| ... | ... | @@ -63,7 +63,11 @@ jobs: |
| 63 | 63 | Windowslatest: |
| 64 | 64 | vmImage: 'windows-2019' |
| 65 | 65 | cli11.std: 20 |
| 66 | - cli11.options: -DCMAKE_CXX_FLAG="/std:c++latest" | |
| 66 | + cli11.options: -DCMAKE_CXX_FLAGS="/std:c++latest /EHsc" | |
| 67 | + Linux17nortti: | |
| 68 | + vmImage: 'ubuntu-latest' | |
| 69 | + cli11.std: 17 | |
| 70 | + cli11.options: -DCMAKE_CXX_FLAGS="-fno-rtti" | |
| 67 | 71 | pool: |
| 68 | 72 | vmImage: $(vmImage) |
| 69 | 73 | steps: | ... | ... |
book/chapters/config.md
| ... | ... | @@ -135,7 +135,7 @@ The default configuration file will read INI files, but will write out files in |
| 135 | 135 | ```cpp |
| 136 | 136 | app.config_formatter(std::make_shared<CLI::ConfigINI>()); |
| 137 | 137 | ``` |
| 138 | -which makes use of a predefined modification of the ConfigBase class which TOML also uses. If a custom formatter is used that is not inheriting from the from ConfigBase class `get_config_formatter_base() will return a nullptr, so some care must be exercised in its us with custom configurations. | |
| 138 | +which makes use of a predefined modification of the ConfigBase class which TOML also uses. If a custom formatter is used that is not inheriting from the from ConfigBase class `get_config_formatter_base() will return a nullptr if RTTI is on (usually the default), or garbage if RTTI is off, so some care must be exercised in its use with custom configurations. | |
| 139 | 139 | |
| 140 | 140 | ## Custom formats |
| 141 | 141 | ... | ... |
include/CLI/App.hpp
| ... | ... | @@ -1374,20 +1374,20 @@ class App { |
| 1374 | 1374 | int exit(const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr) const { |
| 1375 | 1375 | |
| 1376 | 1376 | /// Avoid printing anything if this is a CLI::RuntimeError |
| 1377 | - if(dynamic_cast<const CLI::RuntimeError *>(&e) != nullptr) | |
| 1377 | + if(e.get_name() == "RuntimeError") | |
| 1378 | 1378 | return e.get_exit_code(); |
| 1379 | 1379 | |
| 1380 | - if(dynamic_cast<const CLI::CallForHelp *>(&e) != nullptr) { | |
| 1380 | + if(e.get_name() == "CallForHelp") { | |
| 1381 | 1381 | out << help(); |
| 1382 | 1382 | return e.get_exit_code(); |
| 1383 | 1383 | } |
| 1384 | 1384 | |
| 1385 | - if(dynamic_cast<const CLI::CallForAllHelp *>(&e) != nullptr) { | |
| 1385 | + if(e.get_name() == "CallForAllHelp") { | |
| 1386 | 1386 | out << help("", AppFormatMode::All); |
| 1387 | 1387 | return e.get_exit_code(); |
| 1388 | 1388 | } |
| 1389 | 1389 | |
| 1390 | - if(dynamic_cast<const CLI::CallForVersion *>(&e) != nullptr) { | |
| 1390 | + if(e.get_name() == "CallForVersion") { | |
| 1391 | 1391 | out << e.what() << std::endl; |
| 1392 | 1392 | return e.get_exit_code(); |
| 1393 | 1393 | } |
| ... | ... | @@ -1606,7 +1606,12 @@ class App { |
| 1606 | 1606 | |
| 1607 | 1607 | /// Access the config formatter as a configBase pointer |
| 1608 | 1608 | std::shared_ptr<ConfigBase> get_config_formatter_base() const { |
| 1609 | + // This is safer as a dynamic_cast if we have RTTI, as Config -> ConfigBase | |
| 1610 | +#if defined(__cpp_rtti) || (defined(__GXX_RTTI) && __GXX_RTTI) || (defined(_HAS_STATIC_RTTI) && (_HAS_STATIC_RTTI == 0)) | |
| 1609 | 1611 | return std::dynamic_pointer_cast<ConfigBase>(config_formatter_); |
| 1612 | +#else | |
| 1613 | + return std::static_pointer_cast<ConfigBase>(config_formatter_); | |
| 1614 | +#endif | |
| 1610 | 1615 | } |
| 1611 | 1616 | |
| 1612 | 1617 | /// Get the app or subcommand description | ... | ... |
include/CLI/Option.hpp
| ... | ... | @@ -508,7 +508,7 @@ class Option : public OptionBase<Option> { |
| 508 | 508 | |
| 509 | 509 | /// Can find a string if needed |
| 510 | 510 | template <typename T = App> Option *needs(std::string opt_name) { |
| 511 | - auto opt = dynamic_cast<T *>(parent_)->get_option_no_throw(opt_name); | |
| 511 | + auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name); | |
| 512 | 512 | if(opt == nullptr) { |
| 513 | 513 | throw IncorrectConstruction::MissingOption(opt_name); |
| 514 | 514 | } |
| ... | ... | @@ -550,7 +550,7 @@ class Option : public OptionBase<Option> { |
| 550 | 550 | |
| 551 | 551 | /// Can find a string if needed |
| 552 | 552 | template <typename T = App> Option *excludes(std::string opt_name) { |
| 553 | - auto opt = dynamic_cast<T *>(parent_)->get_option_no_throw(opt_name); | |
| 553 | + auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name); | |
| 554 | 554 | if(opt == nullptr) { |
| 555 | 555 | throw IncorrectConstruction::MissingOption(opt_name); |
| 556 | 556 | } |
| ... | ... | @@ -587,7 +587,7 @@ class Option : public OptionBase<Option> { |
| 587 | 587 | template <typename T = App> Option *ignore_case(bool value = true) { |
| 588 | 588 | if(!ignore_case_ && value) { |
| 589 | 589 | ignore_case_ = value; |
| 590 | - auto *parent = dynamic_cast<T *>(parent_); | |
| 590 | + auto *parent = static_cast<T *>(parent_); | |
| 591 | 591 | for(const Option_p &opt : parent->options_) { |
| 592 | 592 | if(opt.get() == this) { |
| 593 | 593 | continue; |
| ... | ... | @@ -612,7 +612,7 @@ class Option : public OptionBase<Option> { |
| 612 | 612 | |
| 613 | 613 | if(!ignore_underscore_ && value) { |
| 614 | 614 | ignore_underscore_ = value; |
| 615 | - auto *parent = dynamic_cast<T *>(parent_); | |
| 615 | + auto *parent = static_cast<T *>(parent_); | |
| 616 | 616 | for(const Option_p &opt : parent->options_) { |
| 617 | 617 | if(opt.get() == this) { |
| 618 | 618 | continue; | ... | ... |