2016-01-24 3 views
0

Я пытаюсь создать простой способ зарегистрировать все решения 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, не так ли?

+0

Не отвечает Два в принятом ответе в ссылке, которую вы дали решить, что? –

+0

Я так не думаю - ответьте на две сделки с segfault, которая возникает до того, как main() достигнут даже. Моя проблема - это segfault, которая возникает во время выполнения, потому что std :: map пуст из-за того, что Register() никогда не вызывается. Я могу установить точку останова до того, как будет создана проблема ep = ProblemFactory :: getInstance, и ее выполнение не вызовет проблем. Я поставил точку останова в Register(), и выполнение никогда не достигает ее, хотя предполагается, что она дойдет до нее до того, как main() будет даже вызван. – AJS

+0

Почему вы заменили использование оригинальной переменной static в конструкторе с помощью 'Enable()'? – molbdnilo

ответ

0

Выяснил это, хотя я не понимаю, почему решение работает.

я переехал следующую строку:

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); 

С вершины EulerProblem.cpp в нижней части EulerProblem.h и она работала. Кто-нибудь имеет представление о том, почему это так?

+0

Я предполагаю, что из включенных охранников вы включаете 'EulerProblem.h' в нескольких местах. Все эти места должны знать, как инициализировать шаблонную статическую переменную. – StoryTeller

Смежные вопросы