2013-07-05 2 views
2

У меня есть несколько классов в проекте, над которым я работаю; первый класс Solver, первоначально с шаблоном функции, полное определение в файле заголовка Solver, например, так (просто показывая самое необходимое):Проблема с циклической зависимостью C++ с шаблонами функций

solver.h

class Solver { 
    public: 
    template<typename T> 
    void solve(T t); 
} 

template<typename T> 
void Solver::solve(T t) { 
    // implementation here 
} 

Теперь, класс А используется в качестве параметра шаблона для решения шаблона функции следующим образом:

Ah

#include "solver.h" 

class A { 
    private: 
    Solver s; //s is instantiated in constructor 

    public: 
    void doSomething(); 
} 

a.cpp

void A::doSomething() { 
    s.solve<A&>(*this); 
} 

Итак, все это прекрасно и денди, как сейчас, но для целей проекта мне нужно перенести определение шаблона функции solve() в файл реализации (solver.cpp) из файл заголовка. Как я понимаю, что я могу сделать это до тех пор, как я добавить строки, которые четко указано, какие типы будут использоваться с шаблоном функции, следующим образом:

solver.cpp

template<typename T> 
void Solver::solve(T t) { 
    // implementation here 
} 

template void Solver::solve<A&>(A& a); 

Однако это не работа, когда я пытаюсь скомпилировать решатель, потому что для того, чтобы указать A как тип, который я хочу использовать в качестве параметра шаблона в файле solve.cpp, мне нужно, чтобы A не был неполным. Но A требует Solver для того, чтобы даже скомпилировать - поэтому я считаю, что у меня круговая зависимость. Есть ли способ обойти эту проблему?

Я относительно новичок во всем этом, так что успокойте меня, пожалуйста :) Большое спасибо.

ответ

2

Samoth почти правильно, вам нужно class A; ("опережающее объявление").Но только прежде чем использовать его, а не перед классом Solver:

Edited В ответ на замечания, ваш минимальный пример кода слишком минимальна :) Реальная проблема была Header Guards:

#ifndef SOLVER_H_INCLUDED_ 
#define SOLVER_H_INCLUDED_ 

class Solver { 
    public: 
    template<typename T> 
    void solve(T t); 
}; 

#endif // SOLVER_H_INCLUDED_ 

И

// A.h 
#ifndef A_H_INCLUDED_ 
#define A_H_INCLUDED_ 

#include "Solver.h" 

class A { 
    private: 
    Solver s; //s is instantiated in constructor 

    public: 
    void doSomething(); 
}; 

#endif // A_H_INCLUDED_ 


// Solver.cpp 
#include "Solver.h" 

#include "A.h" 

template<typename T> 
void Solver::solve(T t) { 
    // implementation here 
} 

// explicit instantiations  
template void Solver::solve<int>(int); 
// ... 
template void Solver::solve<A&>(A&); 

Это будет работать

// main.cpp 
#include "A.h" 

int main() 
{ 
    A a; 
    a.doSomething(); 
} 
+0

Я пробовал это сделать, но компилятор дал мне «ошибку: недопустимое использование неполного типа« struct A »для каждого момента, когда A ссылается на функцию решения, так как а также «ошибка: форвардная декларация« struct A » – user2548415

+0

А хорошо. Вы упростили выборку. Конечно, вы можете просто включить 'A.h' внутри' Solver.cpp' ** и всегда помнить о защите заголовков. ** (отредактировано) – sehe

+0

sehe, вы замечательный человек. это сработало! огромное спасибо. и да, я упростил пример ... моя ошибка. =/там были защитники заголовка, и я забыл включить их в образец. – user2548415

0

Лучший способ пройти-круговыми зависимостей, чтобы сделать это:

class A; // before the class Solver 

class Solver { 
    public: 
    template<typename T> 
    void solve(T t); 
} 

template<typename T> 
void Solver::solve(T t) { 
    // implementation here 
} 
0

Что вы можете сделать, это:

solver.h

#ifndef SOLVER_H_INCLUDED_ 
    #define SOLVER_H_INCLUDED_ 
    class Solver { 
    public: 
     template<typename T> 
     void solve(T t); 

    }; 
    #include "solver.cpp" 
    #endif 

solver.cpp

#include "solver.h" 

template<typename T> 
void Solver::solve(T t) { 
    // implementation here 
} 

и a.hpp

#ifndef A_H_INCLUDED_ 
    #define A_H_INCLUDED_ 
    #include "solver.h" 
    class A { 
    private: 
     Solver s; //s is instantiated in constructor 

    public: 
     void doSomething() 
     { 
     s.solve(*this); 
     } 
    }; 
    #endif 
+0

Хммм. OP конкретно заявляет, что он «должен» переместить определение своего шаблона в отдельный TU. Что технически не то, что вы здесь делаете – sehe

+0

Alexis: Я пробовал это сделать, но у меня появились следующие ошибки: «переопределение пустоты Solver :: solve (T)» и «void Solver :: solve (T), ранее объявленное здесь» в solve.cpp. также, мне нужно спать ... Я вернусь утром! Спасибо за помощь до сих пор – user2548415

+0

У вас нет больше шаблона void Solver :: решить (T t) { // реализация здесь } в вашем solver.h? вам просто нужно определение в вашем .h @sehe, может быть, ему просто нужно переместить файл, чтобы лучше просмотреть проект – Alexis

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