2016-12-20 2 views
2

Arbeiten an einem Befehlszeilenparser für mich. Ich wusste sofort, dass ich mit diesem Konstrukt Probleme bekommen würde und hoffte, dass jemand Vorschläge für eine Arbeit machen könnte.Initialisieren eines Vektors mit Klassenvorlage verschiedener/unbekannter Typen

Ich möchte die Argumentliste der Parameter (basierend auf einer Vorlage) in einer vector, die möglicherweise eine Vielzahl von verschiedenen Datentypen enthalten. Aber von meinem Verständnis müssen Sie die vector<template<type>> statisch definieren. Gibt es eine Möglichkeit, mehrere Arten zu vermeiden? Hier

ist ein Beispiel dafür, was ich meine:

#include <vector> 
#include <memory> 

namespace clparser 
{ 
    class CommandLine { 
    private: 
     std::vector<Parameter<AnyType??>*> ArgumentList; 

    public: 

     void Add(Parameter<AnyType??>* Parameter) { ArgumentList.push_back(Parameter); } 
    }; 


    template<typename T> 
    class Parameter { 
    private: 
     const char *ShortOption; 
     const char *LongOption; 
     const char *Description; 
     const bool RequiredField; 
     const char *DefaultValue; 


    public: 
     Parameter(const char *ShortOption, const char *LongOption, const char *Description, const bool RequiredField, const char *DefaultValue) 
      : ShortOption(ShortOption), LongOption(LongOption), Description(Description), RequiredField(RequiredField), DefaultValue(DefaultValue) 
     { 

     } 
    }; 
} 
+1

Vielleicht 'boost :: any'? –

+0

Ich würde lieber keine Boost-Abhängigkeiten haben, aber wenn ich das mit der STL nicht schaffen kann ... Danke, – user0000001

+0

Da C++ 17 'any' auch in' std' verfügbar sein wird –

Antwort

0

Wenn Sie eine C++ 11-Lösung akzeptieren kann, schlage ich vor, Sie eine iper vereinfachte Version von meinem Befehlszeilenparser. Hoffe, dass das für dich Inspiration sein kann.

Die Idee hinter meiner Lösung ist die Verwendung von Base/abgeleitet Polymorphismus: ein rein virtuellen class optBase, die eine Basis für eine Reihe von Template-Klassen Optionen gewidmet ist (im folgende Beispiel nur class opt, aber es gibt auch andere drei in mein Parser).

Dann wird die (nicht Vorlage) class yData enthält ein std::unique_ptr<optBase> (wenn Sie einen einfachen Zeiger auf optBase verwenden, können Sie kompilieren in C++ 98 zu, nehme ich an, aber ich schlage vor, die Verwendung von C++ 11 oder höher).

class yData entsprechen (grob) zu Ihrem tou Ihre class Parameter aber (hier ist der Trick) ist keine Vorlagenklasse; einen Basiszeiger auf eine Vorlagenklasse enthalten.

Meine class yarg entsprechen Ihrer class clparser und meine std::map<int, yData> idMap entsprechen (grob) Ihrer std::vector<Parameter<AnyType??>*> ArgumentList.

Um idMap zu füttern, habe ich eine Reihe von Vorlage-Methode entwickelt (eine für jede abgeleitete von optbase Klassen); Im folgenden Beispiel sehen Sie eine iper-vereinfachte Version von einem von ihnen: addOpt() (entspricht in etwa Ihrer Add()).

Im folgenden Beispiel Sie ein wenig main() mit ein paar Anwendungen für addOpt() sehen: der erste für einen int Parameter und die zweite für einen double Parameter (wichtig (und Schwachpunkt meiner Lösung): Der Rückgabewert muss in einer Referenz Variable gespeichert werden, nicht in einer einfachen Variablen).

#include <map> 
#include <memory> 


    class optBase 
    { 
     public: 
     // some pure virtual methods 
    }; 

    template <typename X> 
    class opt : public optBase 
    { 
     private: 
     X val { }; 
     // ... 

     public: 

     opt() 
      { } 

     opt (X const & v0) 
      : val { v0 } // ... 
      { } 

     X const & getVal() const 
      { return val; } 

     X & getVal() 
      { return val; } 

     // ... 
    }; 

    // other optBase derived classes (for flags, containers of values, etc) 

    class yData 
    { 
     private: 
     // ... 
     std::unique_ptr<optBase> optB; 

     public: 
     yData (/* other arguments */ std::unique_ptr<optBase> optB0) 
      : /* something else */ optB { std::move(optB0) } 
      { } 
     // ... 
     std::unique_ptr<optBase> const & getPnt() const 
      { return optB; } 
    }; 

    class yarg 
    { 
     private: 
     // ... 
     std::map<int, yData> idMap; 
     // ... 

     public: 
     // ... 
     template <typename T> 
     T & addOpt (/* other arguments */ T const & def = T()) 
      { 
      int  id { /* some value */ }; 
      opt<T> * optP { nullptr }; 
      // ...& 
      idMap.emplace(std::piecewise_construct, 
        std::forward_as_tuple(id), 
        std::forward_as_tuple(/* other arguments */ 
        std::unique_ptr<optBase>(optP = new opt<T>(def)))); 

      return optP->getVal(); 
      } 

    }; 

int main() 
{ 
    yarg y; 

    // important: use a *reference* 
    auto & pi = y.addOpt(3); // pi is a int 
    auto & pd = y.addOpt(3.0); // pd is a double 

    static_assert(std::is_same<decltype(pi), int &>::value, "!"); 
    static_assert(std::is_same<decltype(pd), double &>::value, "!!"); 
} 
Verwandte Themen