C++ 11模板变量设计

use*_*410 3 c++ c++11

我有很多抽象类字母的子类,如A,B,C,D等.字母有一个整数ID变量,并且Letter的每个子类都被赋予一个唯一的id.

然后我有另一个班,称之为Alphabet.字母表有一个

list<shared_ptr<Letter>> 
Run Code Online (Sandbox Code Playgroud)

会员.这是问题...我想优雅地将B和C或其他子类的Letter添加到字母的特定实例中.我认为最方便的方法是以某种方式使用子类的整数id.换句话说,我希望能够有像Alphabet.addLetter(int id)这样的东西,所以如果我做了alphabet1.add(14),它会以某种方式将H类的shared_ptr添加到列表中.

有没有一种优雅的方法来做到这一点,避免一些巨大的if语句,我需要不断更新每次添加或删除B,C,D,E等类之一?我希望有一些模板解决方案,但我不熟悉工厂和模板等高级c ++概念.我想要的天真的东西是某种矢量/地图,它将我的id转换为类名,这样我就可以做类似的事情

list.push_back(shared_ptr<classVector(i)>(new classVector(i))
Run Code Online (Sandbox Code Playgroud)

或类似的东西,虽然我不知道这是否可能.

谢谢!

ps我刚刚选择了Alphabet示例,因为我不想给出不必要的细节.显然,我不是试图以这种愚蠢的方式设计字母表,哈哈.

编辑:我正在努力使这有意义.我的目标是能够以最小的努力快速创建Letter的新子类.我想避免输入看起来像......的代码

list.push_back(shared_ptr<X>(...));
Run Code Online (Sandbox Code Playgroud)

每次我写一封新信.这有意义吗?

Jef*_*eff 8

这很难遵循,但我认为您想要的是以下内容:

// where make_unique<> is from C++14 in std:: or like:
template <typename T, typename ... TArgs>
std::unique_ptr<T> make_unique(TArgs &&... args) {
  return std::unique_ptr<T>(new T(std::forward<TArgs>(args)...));
}

struct Letter {
  virtual ~Letter() { }
  virtual void foo() = 0;
};
template <unsigned int N> struct LetterCode; // Note: no default implementation!

struct Alphabet {
  // Indexed access, if you'll have 1 of each type max:
  std::vector<std::unique_ptr<Letter>> v;

  // If you don't need parameters, as mentioned in comments below ...
  template <unsigned int N>
  void addLetterN() {
    if (N > v.size() + 1) { v.resize(N + 1); }
    v[N] = make_unique<LetterCode<N>::type>(); // see below ...
  }

  // If your coding is complete from 0...N, this does the whole shebang.
  template <unsigned int N>
  void addLettersN() {
    addLetters<N - 1>();
    addLetterN<N>();
  }
  template <>
  addLettersN<0>() {
    addLetterN<0>();
  }
};
Run Code Online (Sandbox Code Playgroud)

如果您需要反序列化之类的数字代码并且永远不需要构造函数参数,则可以使用类似以下的类型特征模板来静态"注册"类型:

struct B : Letter {
  B(int n, bool b, char const *name);
  void foo() override;
};
template <> struct LetterCode<2> { using type = B; };

struct C : Letter {
  C(double d);
  void foo() override;
};
template <> struct LetterCode<3> { using type = C; };

void bar() {
  Alphabet a;
  a.addLetterN<2>();
  a.addLetterN<3>();

  // --OR--
  a.addLettersN<3>(); // will do 0...3 in one fell swoop.

  for (auto &i : a.v) {
    if (!i) { continue; } // v is sparse, unlike l
    i->foo();
}
Run Code Online (Sandbox Code Playgroud)

如果你需要通用的构造函数参数传递,你可以使用完美转发,这是为这样的情况设计的,并且不需要来自旧式工厂的枚举ID等:

struct Alphabet {
  std::list<std::unique_ptr<Letter>> l;

  // variadic factory that chucks new (shared_ptr) objects in the list.
  template <typename T, typename ... TArgs>
  void addLetter(TArgs && ... args) {
    l.push_back(make_unique<T>(std::forward<TArgs>(args)...));
  }
};

void baz() {
  Alphabet a;
  a.addLetter<B>(1, false, "pony");
  a.addLetter<C>(2.718281828);

  for (auto &i : a.l) {
    i->foo(); // can call virtual funcs here all you want ...
  }
}
Run Code Online (Sandbox Code Playgroud)