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

Receive udp packets in android gstreamer -

php - Extract Text from HTTP referer -

matplotlib - PYTHON: Annotate boxes disapear dependant on range -