diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3d6eabc..d8637ae 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -63,7 +63,11 @@ jobs: Windowslatest: vmImage: 'windows-2019' cli11.std: 20 - cli11.options: -DCMAKE_CXX_FLAG="/std:c++latest" + cli11.options: -DCMAKE_CXX_FLAGS="/std:c++latest /EHsc" + Linux17nortti: + vmImage: 'ubuntu-latest' + cli11.std: 17 + cli11.options: -DCMAKE_CXX_FLAGS="-fno-rtti" pool: vmImage: $(vmImage) steps: diff --git a/book/chapters/config.md b/book/chapters/config.md index a9edf9a..fd2dbd7 100644 --- a/book/chapters/config.md +++ b/book/chapters/config.md @@ -135,7 +135,7 @@ The default configuration file will read INI files, but will write out files in ```cpp app.config_formatter(std::make_shared()); ``` -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. +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. ## Custom formats diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index ad4d950..54ac703 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -1374,20 +1374,20 @@ class App { int exit(const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr) const { /// Avoid printing anything if this is a CLI::RuntimeError - if(dynamic_cast(&e) != nullptr) + if(e.get_name() == "RuntimeError") return e.get_exit_code(); - if(dynamic_cast(&e) != nullptr) { + if(e.get_name() == "CallForHelp") { out << help(); return e.get_exit_code(); } - if(dynamic_cast(&e) != nullptr) { + if(e.get_name() == "CallForAllHelp") { out << help("", AppFormatMode::All); return e.get_exit_code(); } - if(dynamic_cast(&e) != nullptr) { + if(e.get_name() == "CallForVersion") { out << e.what() << std::endl; return e.get_exit_code(); } @@ -1606,7 +1606,12 @@ class App { /// Access the config formatter as a configBase pointer std::shared_ptr get_config_formatter_base() const { + // This is safer as a dynamic_cast if we have RTTI, as Config -> ConfigBase +#if defined(__cpp_rtti) || (defined(__GXX_RTTI) && __GXX_RTTI) || (defined(_HAS_STATIC_RTTI) && (_HAS_STATIC_RTTI == 0)) return std::dynamic_pointer_cast(config_formatter_); +#else + return std::static_pointer_cast(config_formatter_); +#endif } /// Get the app or subcommand description diff --git a/include/CLI/Option.hpp b/include/CLI/Option.hpp index 911dd64..826b5e1 100644 --- a/include/CLI/Option.hpp +++ b/include/CLI/Option.hpp @@ -508,7 +508,7 @@ class Option : public OptionBase