-
Notifications
You must be signed in to change notification settings - Fork 397
Description
std::string files;
auto opt = app.add_option("-f,--file,file", files, "File name");
opt->take_first();
opt->take_last();
opt->join();
The above code snipet will throw an exception from multi_option_policy method in Option class. In fact take_first, take_last and join can only be called once. According to the docs, these methods will only be used for vectors(may be flags). So it is better to hide these interfaces in other situations, or fix these bug.
To wholy avoid these interface conflict, a refactor to the Option level is needed. Option class itself or its internal implementation need different types to provide polymorphism. I want to help implement the enhancement, but some part of the source code is still unclear to me, especially type_size_ expected_ and their relationship with multi_option_policy_, would you give some hints about these? Thanks!
The following is a possible implementation. It seems like an enhanced version of CRTP, but with an important differnce. These base classes themselves can inherite from each other, so the code organization is similar to a virtual function based method, but with static dispatching.
Please gives your feedback, thanks again!
template<typename Host>
struct CommonStrategy {
//common data
bool configurable_{true};
std::vector<std::string> snames_;
//common behavior
bool configurable() const { return configurable_; }
void configurable(bool val) { configurable_ = val; }
};
template<typename Host>
struct OptionStrategy : public CommonStrategy<Host> {
//customized behavior
std::string get_names() {
std::ostringstream out;
//access common data
auto &self = static_cast<Host&>(*this);
for(auto &name: self.snames) {
out << name << ",";
}
return out.str();
}
};
template<typename Host>
struct FlagStrategy : public CommonStrategy<Host> {
//customized behavior
std::string get_names() {
std::ostringstream out;
//access common data snames_
auto &self = static_cast<Host&>(*this);
for(auto &name: self.snames_) {
out << name << ",";
}
//access extra data fnames_
for(auto &name : fnames_) {
out << name << ",";
}
return out.str();
}
//extra data
std::vector<std::string> fnames_;
//extra behavior
const std::vector<std::string> & get_fnames() const {
return fnames_;
}
};
template<template<typename> class Strategy>
struct Host : public Strategy<Host<Strategy>> {
};
int main() {
Host<FlagStrategy> flag;
flag.configurable(false);//call common method
flag.get_names();//will prints name in a specific way
flag.get_fnames();//call the extra method specific to FlagStrategy
Host<OptionStrategy> option;
option.configurable(false);//call common method
option.get_names();//will prints name in another way
//option.get_fnames();//this method does even exists for ordinary Options
return 0;
}