Я пытаюсь создать простой способ зарегистрировать все решения Project Euler в std :: map в заводском шаблоне, чтобы иметь возможность ссылаться на них в коде по номеру. Я нашел фантастический ответ на этом сайте (Dynamically register constructor methods in an AbstractFactory at compile time using C++ templates) и пришел к этому решению:Занятия не регистрируются на заводе
EulerProblem.h:
#ifndef EULERPROBLEM_H
#define EULERPROBLEM_H
#include<string>
#include<sstream>
#include<QObject>
#include<QString>
// BASE PROBLEM CLASS
class EulerProblem : public QObject
{
Q_OBJECT
signals:
void printSignal(QString str);
void debugSignal(QString str);
void problemTextSignal(QString str);
protected:
EulerProblem() {}
void print(QString str);
void debug(QString str);
void setProblemText(QString str);
protected:
int problemNumber;
QString problemText;
public:
virtual ~EulerProblem() { }
void initialize();
virtual void doProblem() = 0;
};
// PROBLEM TEMPLATE, DERIVE PROBLEMS FROM THIS
template<int NUM, typename IMPL>
class ProblemTmpl : public EulerProblem
{
enum { _PROBLEM_ID = NUM };
public:
static EulerProblem* Create() { return new IMPL(); }
static const uint16_t PROBLEM_ID; // for registration
// static void Enable() { volatile uint16_t x = PROBLEM_ID; }
protected:
ProblemTmpl() { problemNumber = PROBLEM_ID; } //use parameter to instantiate template
};
// PROBLEM FACTORY, USE THIS TO GET PROBLEMS
class ProblemFactory
{
public:
typedef EulerProblem* (*t_pfFactory)();
static ProblemFactory *getInstance()
{
static ProblemFactory fact;
return &fact;
}
uint16_t Register(uint16_t msgid, t_pfFactory factoryMethod)
{
printf("Registering constructor for msg id %d\n", msgid);
m_List[msgid] = factoryMethod;
return msgid;
}
EulerProblem *Create(uint16_t msgid)
{
return m_List[msgid]();
}
std::map<uint16_t, t_pfFactory> m_List;
private:
ProblemFactory() {};
ProblemFactory(ProblemFactory const&) {};
ProblemFactory& operator=(ProblemFactory const&);
~ProblemFactory() {};
};
#endif // EULERPROBLEM_H
EulerProblem.cpp (обратите внимание на первую строку, которая предназначена для автоматического вызова Register()
) :
#include "eulerproblem.h"
template <int TYPE, typename IMPL>
const uint16_t ProblemTmpl<TYPE, IMPL>::PROBLEM_ID =
ProblemFactory::getInstance()->Register(ProblemTmpl<TYPE, IMPL>::_PROBLEM_ID, &ProblemTmpl<TYPE, IMPL>::Create);
void EulerProblem::initialize()
{
setProblemText(problemText);
}
void EulerProblem::debug(QString str)
{
emit debugSignal(str);
}
void EulerProblem::print(QString str)
{
emit printSignal(str);
}
void EulerProblem::setProblemText(QString str)
{
emit problemTextSignal(str);
}
Пример проблема класса (049.h):
#ifndef _49_h
#define _49_h
class Problem049 : public ProblemTmpl<49, Problem049>
{
public:
Problem049()
{
problemText =
"The arithmetic sequence, 1487, 4817, 8147, in which each of the terms increases by 3330, is unusual in two ways: (i) each of the three terms are prime, and, (ii) each of the 4-digit numbers are permutations of one another.\n"
"\n"
"There are no arithmetic sequences made up of three 1-, 2-, or 3-digit primes, exhibiting this property, but there is one other 4-digit increasing sequence.\n"
"\n"
"What 12-digit number do you form by concatenating the three terms in this sequence?";
}
void doProblem()
{
// problem solution here
}
};
#endif /* _49_h */
Так что, когда я использую следующий код (в connect()
звонках Qt материал для разводки сигналов):
ep = ProblemFactory::getInstance()->Create(49);
connect(ep, SIGNAL(printSignal(QString)), this, SLOT(addOutput(QString)));
connect(ep, SIGNAL(debugSignal(QString)), this, SLOT(addDebug(QString)));
connect(ep, SIGNAL(problemTextSignal(QString)), this, SLOT(setProblem(QString)));
ep->initialize();
Я получаю Segfault от ProblemFactory::Create()
, потому что std::map
пуста - Регистрация() никогда не вызывались. Однако код компилируется. Может ли кто-нибудь увидеть, что я здесь делаю неправильно? Некоторое время я охотился.
Я запустил и скомпилировал пример, приведенный как ответ в другом вопросе, и он отлично работает. Это не что-то противоречивое с Qt, не так ли?
Не отвечает Два в принятом ответе в ссылке, которую вы дали решить, что? –
Я так не думаю - ответьте на две сделки с segfault, которая возникает до того, как main() достигнут даже. Моя проблема - это segfault, которая возникает во время выполнения, потому что std :: map пуст из-за того, что Register() никогда не вызывается. Я могу установить точку останова до того, как будет создана проблема ep = ProblemFactory :: getInstance, и ее выполнение не вызовет проблем. Я поставил точку останова в Register(), и выполнение никогда не достигает ее, хотя предполагается, что она дойдет до нее до того, как main() будет даже вызван. – AJS
Почему вы заменили использование оригинальной переменной static в конструкторе с помощью 'Enable()'? – molbdnilo