C ++编译时模板多态

时间:2016-04-04 11:43:57

标签: c++ templates containers

我想创建一个应用程序,在其中我可以定义键入的问题列表,然后迭代此列表并要求用户输入答案,将它们存储在另一个列表中,然后检查答案,验证它们并提供结果。

我目前的天真态度是这样的:

class Question {
  std::string message;
public:
  Question(const std::string& msg) : message{msg} {}
  std::string& getQuestion(void) const {
    return this->message;
  }
  virtual ~Question(void) = 0;
};

Question::~Question(void) {}

template<class AnswerType>
class Prompt : public Question {
   Prompt(std::string& msg) : Question{msg} {}
   virtual ~Prompt(void) {}
};

class Answer<class T> {
  T answ;
public:
  Answer(const T& answer) : answ{answer} {}
  T getAnswer(void) const {
    return this->answ;
  }
};

我想做类似的事情:

std::list< const Question* > whatToAsk{
  new Prompt<int>{"Your age"},
  new Prompt<std::string>{"Your name"},
  new Prompt<float>{"Your weight"}
};

for(auto q in whatToAsk) {
  Answer< "derived q template parameter" > a{};
  std::cout << q->getQuestion() << ": ";
  std::cin >> a;
  // ... to be continued ...
}

std :: list&lt;内部存储问题(提示&lt; T&gt; ) const问题*&gt;

但对我来说有问题的部分是我要使用向下转换(使用运行时检查),虚函数(运行时多态)或双重调度(再次使用运行时开销)。

我担心的是类型在编译时是已知的,因为问题列表将在源代码中进行硬编码,我希望避免运行时开销并实现编译时静态多态。

我怎样才能做到这一点?某种特质可能吗?

4 个答案:

答案 0 :(得分:2)

如果您不想使用虚拟功能/ "version": "1.0.0.24",,则应

  1. 将每个问题设为不同类型。
  2. 将它们存储在元组中,而不是列在列表中。
  3. 使用特殊功能进行迭代(dynamic_cast - 它是可谷歌的)。
  4. 使用虚函数执行此操作要简单得多,除非您有数千个问题,否则运行时开销可以忽略不计。

答案 1 :(得分:1)

我不是专家,但也许您可以使用c ++ 11可变参数模板,这些模板允许您拥有不同类型的数组,因此不会因为向下转换而产生任何开销。

此链接可能会让您感兴趣Create static array with variadic templates

答案 2 :(得分:1)

一些稀疏的笔记,不仅仅是一个回复

添加答案处理东西部分的问题成员函数。这样您就可以知道问题的类型。像

这样的东西
void ask()
{
    Answer<T> answer ; 
    std::cint >> a ;
    ....
}

使用std :: shared_ptr而不是普通指针。

可能一个被称为虚拟构造函数的成语作为问题工厂可能有助于构建问题

这样的东西
Question *make_question(int type)
{
   switch (type)
   {
      case 0: return new Prompt<int>() ; 
      case 1: return new Prompt<std::string>() ;
      ...
    }
}

答案 3 :(得分:1)

如果你使用的是c ++ 14,你可以这样做:

#include <iostream>

template <class FirstQuestion, class... OtherQuestions>
struct QuestionList {
   template <class Functor>
   void foreach(Functor &&functor) {
      functor(FirstQuestion());
      QuestionList<OtherQuestions...> oql;
      oql.foreach(functor);
   }
};

template <class FirstQuestion>
struct QuestionList<FirstQuestion> {
   template <class Functor>
   void foreach(Functor &&functor) {
      functor(FirstQuestion());
   }
};



template <class AnswerType, const char *QuestionString>
struct Question {
   static AnswerType answer;
   static void print_question() {
      std::cout << QuestionString << std::endl;
   }
   static void get_answer() {
      std::cin >> answer;
   }
};

template <class AnswerType, const char *QuestionString>
AnswerType Question<AnswerType, QuestionString>::answer;

constexpr char questionstrings1[] = "lorem";
constexpr char questionstrings2[] = "ipsum";

int main() {
  QuestionList<Question<int, questionstrings1>, Question<float, questionstrings2> > a;
  a.foreach([](auto x){ x.print_question(); x.get_answer(); });
}

要在循环中访问答案,您可以简单地:

a.foreach([](auto x){ /*doing something with x.answer*/ };

PS请记住,提示用户提供答案会导致非运行时多态性的潜在效率......