c++ - Saving class instances with different template parameters inside one vector but keep their properties -


i have program parses , manages command-line parameters me. can see in main-function, using simple commands option<int>("number", { "-n", "--number" }) can specify type option's value should have (like int in case), unique identifier each option (like "number"), , multiple strings option can introduced with. also, many options should wrapped in class called optionset, simplifies access options.

but in actual code, having several problems right now:

  1. i want store multiple instances of 1 class different template parameters within 1 std::vector. example, in code, option<int> should stored in same vector option<std::string> , option<double>.
    maybe it's possible store template parameters separately in vector?
  2. by using using, std::enable_if_t , std::is_same created type called optionhasvalue. if template parameter invert false , t void, optionhasvalue has invalid type, otherwise has type specified template parameter u.
    class optionvalue uses optionhasvalue , bit of sfinae magic decide if should have needed methods supporting storage of values or not. is, first version of optionvalue has optionhasvalue<t> second template parameter, becomes invalid (and removed compiler) if t void. other version of optionvalue has opposite behavior, because second template parameter optionhasvalue<t, true> , true inverts behavior of optionhasvalue.
    class option inherits optionvalue, if create option option<void>, not have support values (that is, lacks functions setvalue, setvaluefromstring , getvalue should). on other hand, if create option option<int>, resulting class instance has of these features.
    problem is, (for example) optionset::process() accesses both option::hasvalue , option::setvaluefromstring, latter declared if option::hasvalue true (and corresponding template parameter option not void). because option::setvaluefromstring not wrapped in kind of template here, compiler complains.
  3. in main-function use function optionset.getoptionvalue(std::string). function should return value of option (after has been set after process() has been called). difficult thing return type depends on return value of findoptionbyidentifier, function loops through available options , returns option wanted identifier.
    example, if identifier "number" (as in example option @ beginning of question), return type of findoptionbyidentifier option<int>, because option having identifier "number" 1 has int first template parameter, result in getoptionvalue having return type int.
    can see expected behavior in comments in of last lines of main-function.

so, have change in following code fix these things (and make compile)? using g++ 5.2.0 (mingw-w64), may use feature of c++11 , c++14.

#include <iostream> #include <vector> #include <string> #include <algorithm> #include <stdexcept> #include <type_traits> #include <boost/lexical_cast.hpp> #include <boost/any.hpp>    template<typename t, bool invert = false, typename u = void> using optionhasvalue = std::enable_if_t<(!std::is_same<t, void>::value) ^ invert, u>;       //only make template substitution successful, if (when 'invert' false) t not if type 'void'  template<typename t, typename enable = void> class optionvalue;  template<typename t> class optionvalue<t, optionhasvalue<t>>             //using sfinae ("substitution failure not error") here {     protected:         t                               value;      public:         void setvalue(t newvalue)         {             value = newvalue;         }          void setvaluefromstring(std::string newvaluestr)         {             setvalue(boost::lexical_cast<t>(newvaluestr));         }          t getvalue()         {             return value;         }          bool hasvalue()         {             return true;                            //if class variant taken compiler, 'option' inherit have value         } };  template<typename t> class optionvalue<t, optionhasvalue<t, true>>       //the opposite condition (the 'true' inverts it) {     //option value disabled, check if value available in derived class, add function (or should not?)     public:         bool hasvalue()         {             return false;         } };    template<typename t> class option : public optionvalue<t> {     private:         std::string                     identifier;         std::vector<std::string>        variants;      public:         option(std::string newidentifier, std::vector<std::string> newvariants)         {             identifier = newidentifier;             variants = newvariants;         }          bool hasvariant(std::string v)         {             return (std::find(variants.begin(), variants.end(), v) != variants.end());         }          std::string getidentifier()         {             return identifier;         } };    class optionset {     private:         std::vector<boost::any>         options;                                //boost::any can't right way this, or it?         std::vector<std::string>        argvvec;          template<typename t>         option<t>& findoptionbyidentifier(std::string identifier)         {             for(auto& o : options)                 if(o.getidentifier() == identifier)                             //of course doesn't compile, because 'o' of type 'boost::any', should instead?                     return o;             throw std::runtime_error("error: unable find option identifier \"" + identifier + "\"\n");         }          template<typename t>         option<t>& findoptionbyvariant(std::string variant)         {             for(auto& o : options)                 if(o.hasvariant(variant))                                       //probably same compile error in 'findoptionbyidentifier'                     return o;             throw std::runtime_error("error: unable find option variant \"" + variant + "\"\n");         }      public:         template<typename t>         void add(option<t> opt)         {             options.push_back(opt);                                             //is right way add instances of classes different template parameters vector?         }          void setargvvec(std::vector<std::string> newargvvec)         {             argvvec = newargvvec;         }          void process()         {             for(size_t i=0; i<argvvec.size(); i++)             {                 option<t>& opt = findoptionbyvariant(argvvec[i]);               //of course doesn't compile either, should instead?                 if(opt.hasvalue())                 {                     if(i == argvvec.size()-1)                         throw std::runtime_error("error: no value given option \"" + argvvec[i] + "\"\n");                     opt.setvaluefromstring(argvvec[i]);                         //boost::bad_lexical_cast should caught here, that's not important right                     i++;                 }             }         }          template<typename t>         t getoptionvalue(std::string identifier)         {             option<t>& opt = findoptionbyidentifier(identifier);                //a bit call 'findoptionbyvariant' in 'process()'. also, variable not have reference             if(!opt.hasvalue())                 throw std::runtime_error("error: option identifier \"" + identifier + "\" has no value\n");             return opt.getvalue();         } };    int main() {     optionset optionset;      //it's not guaranteed optionset::add receive rvalue, here shorter code/simplicity     optionset.add(option<void>("help", { "-?", "--help" }));                    //if it's void-option, 'option' not have value, if template parameter else, has 1 (like below)     optionset.add(option<std::string>("message", { "-m", "--message" }));     optionset.add(option<int>("number", { "-n", "--number" }));     optionset.add(option<double>("pi", { "-p", "--pi" }));      optionset.setargvvec({ "--help", "-m", "hello", "--number", "100", "--pi", "3.14" });     optionset.process();      std::string message = optionset.getoptionvalue("message");     int number = optionset.getoptionvalue("number");     double pi = optionset.getoptionvalue("pi");      std::cout << "message: " << message << "\n";        //should output 'hello'     std::cout << "number:  " << number << "\n";         //should output '100'     std::cout << "pi:      " << pi << "\n";             //should output '3.140000'      return 0; } 

i not sure understood question, try answer it.

i want store multiple instances of 1 class different template parameters

there no such thing. template different template paramter different class. however, seem solving through boost::any. use type-erasure technique - example, have non-template parent options, or switch non-type-erasure boost::variant, seems have limited number of possible option types.

by using using, std::enable_if_t , std::is_same created type called optionhasvalue...

first of all, not use sfinae in example. simple partial specialization suffice. opt.setvaluefromstring(argvvec[i]); create noop function in void option class.

as last question, use templated function receives reference return type, instead of returning it.


Comments

Popular posts from this blog

authentication - Mongodb revoke acccess to connect test database -

r - Update two sets of radiobuttons reactively - shiny -

ios - Realm over CoreData should I use NSFetchedResultController or a Dictionary? -