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>
This commit is contained in:
Ondřej Čertík 2020-06-01 19:24:57 -06:00 committed by GitHub
parent 611431ceb0
commit 5c35c182f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 19 additions and 10 deletions

View File

@ -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:

View File

@ -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<CLI::ConfigINI>());
```
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

View File

@ -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<const CLI::RuntimeError *>(&e) != nullptr)
if(e.get_name() == "RuntimeError")
return e.get_exit_code();
if(dynamic_cast<const CLI::CallForHelp *>(&e) != nullptr) {
if(e.get_name() == "CallForHelp") {
out << help();
return e.get_exit_code();
}
if(dynamic_cast<const CLI::CallForAllHelp *>(&e) != nullptr) {
if(e.get_name() == "CallForAllHelp") {
out << help("", AppFormatMode::All);
return e.get_exit_code();
}
if(dynamic_cast<const CLI::CallForVersion *>(&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<ConfigBase> 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<ConfigBase>(config_formatter_);
#else
return std::static_pointer_cast<ConfigBase>(config_formatter_);
#endif
}
/// Get the app or subcommand description

View File

@ -508,7 +508,7 @@ class Option : public OptionBase<Option> {
/// Can find a string if needed
template <typename T = App> Option *needs(std::string opt_name) {
auto opt = dynamic_cast<T *>(parent_)->get_option_no_throw(opt_name);
auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
if(opt == nullptr) {
throw IncorrectConstruction::MissingOption(opt_name);
}
@ -550,7 +550,7 @@ class Option : public OptionBase<Option> {
/// Can find a string if needed
template <typename T = App> Option *excludes(std::string opt_name) {
auto opt = dynamic_cast<T *>(parent_)->get_option_no_throw(opt_name);
auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
if(opt == nullptr) {
throw IncorrectConstruction::MissingOption(opt_name);
}
@ -587,7 +587,7 @@ class Option : public OptionBase<Option> {
template <typename T = App> Option *ignore_case(bool value = true) {
if(!ignore_case_ && value) {
ignore_case_ = value;
auto *parent = dynamic_cast<T *>(parent_);
auto *parent = static_cast<T *>(parent_);
for(const Option_p &opt : parent->options_) {
if(opt.get() == this) {
continue;
@ -612,7 +612,7 @@ class Option : public OptionBase<Option> {
if(!ignore_underscore_ && value) {
ignore_underscore_ = value;
auto *parent = dynamic_cast<T *>(parent_);
auto *parent = static_cast<T *>(parent_);
for(const Option_p &opt : parent->options_) {
if(opt.get() == this) {
continue;