【问题标题】:Initializing a vector with class template of different / unknown types使用不同/未知类型的类模板初始化向量
【发布时间】:2017-05-05 21:13:14
【问题描述】:

为我自己开发一个命令行解析器。我马上就知道我在使用这个结构时会遇到问题,并希望有人可以提供解决方法的建议。

我想将参数的参数列表(基于模板)存储在可能包含各种不同数据类型的vector 中。但据我了解,您必须静态定义vector<template<type>>。有没有办法排除多种类型?

这是我的意思的一个例子:

#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)
        {

        }
    };
}

【问题讨论】:

  • 可能是boost::any?
  • 我宁愿没有任何 boost 依赖,但如果我不能用 STL 完成这个...谢谢
  • c++17 起any 也将在std 中提供
  • 太棒了。感谢您的快速响应!
  • 如果你知道类型,考虑使用 std::variant

标签: c++ class templates


【解决方案1】:

如果您可以接受 C++11 解决方案,我建议您使用我的命令行解析器中的 iper 简化版本。希望对您有所启发。

我的解决方案背后的想法是使用基/派​​生多态性:纯虚拟class optBase 是一组专用于选项的模板类的基础(在以下示例中,只有class opt;但有我的解析器中的其他三个)。

然后(不是模板)class yData 包含一个std::unique_ptr&lt;optBase&gt;(如果您使用指向optBase 的简单指针,我想您也可以在 C++98 中编译;但我建议使用 C++ 11 或更高版本)。

class yData (大致)对应于您的class Parameter,但(这是诀窍)不是模板类;包含一个指向模板类的基指针。

我的class yarg 对应于你的class clparser,我的std::map&lt;int, yData&gt; idMap 对应于(大致)你的std::vector&lt;Parameter&lt;AnyType??&gt;*&gt; ArgumentList

为了喂idMap,我开发了一套模板方法(每个派生自optbase 类);在以下示例中,您可以看到其中之一的 iper 简化版本:addOpt()(大致对应于您的 Add())。

在下面的示例中,您可以看到一个小的main(),其中addOpt() 有几个用法:第一个用于int 参数,第二个用于double 参数(重要(也是我的弱点)解决方案):返回值必须保存在reference变量中,而不是简单变量中)。

#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, "!!");
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-26
    • 2023-01-23
    • 1970-01-01
    • 2021-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多