У меня есть несколько классов в проекте, над которым я работаю; первый — это класс Solver, изначально с шаблоном функции, полное определение которого находится в заголовочном файле Solver, вот так (просто показывая все необходимое):
solver.h
class Solver {
public:
template<typename T>
void solve(T t);
}
template<typename T>
void Solver::solve(T t) {
// implementation here
}
Теперь класс A используется в качестве параметра шаблона для шаблона функции решения следующим образом:
хиджры
#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 для того, чтобы даже компилировать — поэтому я считаю, что у меня круговая зависимость. Есть ли способ обойти эту проблему?
Я относительно новичок во всем этом, так что успокойся, пожалуйста 🙂 Большое спасибо.
Самот почти прав, тебе нужно class A;
(«предварительная декларация»). Но только перед его использованием, а не перед классом Solver:
отредактированный В ответ на комментарии ваш минимальный пример кода был слишком минимальным 🙂 Реальная проблема была Страж заголовка:
#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();
}
Лучший способ обойти циклические зависимости — сделать это:
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
}
Что вы можете сделать, это:
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