#c #templates #c 17 #smart-pointers
Вопрос:
У меня есть распорядок дня в main.cpp где пользователь укажет, какой режим выполнять в программе. Как только режим указан, будет выполнен соответствующий блок — сначала передайте родительский решатель дочернему решателю и вызовите соответствующий solve
метод в дочернем классе.
std::unique_ptr<SudokuSolver> solver;
if (mode == MODES::SEQUENTIAL_BACKTRACKING)
{
solver = std::make_unique<SudokuSolver_SequentialBacktracking>();
SudokuSolver_SequentialBacktracking* child_solver = dynamic_cast<SudokuSolver_SequentialBacktracking*>(solver.get());
child_solver->solve(board);
}
else if (mode == MODES::SEQUENTIAL_BRUTEFORCE)
{
solver = std::make_unique<SudokuSolver_SequentialBruteForce>();
SudokuSolver_SequentialBruteForce* child_solver = dynamic_cast<SudokuSolver_SequentialBruteForce*>(solver.get());
child_solver->solve(board);
}
else if (mode == MODES::PARALLEL_BRUTEFORCE)
{
int NUM_THREADS = (argc >= 5) ? std::stoi(argv[4]) : 2;
omp_set_num_threads(NUM_THREADS);
#pragma omp parallel
{
#pragma omp single nowait
{
solver = std::make_unique<SudokuSolver_ParallelBruteForce>();
SudokuSolver_ParallelBruteForce* child_solver = dynamic_cast<SudokuSolver_ParallelBruteForce*>(solver.get());
child_solver->solve(board);
}
}
}
else if (mode == MODES::SEQUENTIAL_DANCINGLINKS)
{
solver = std::make_unique<SudokuSolver_SequentialDLX>(board);
SudokuSolver_SequentialDLX* child_solver = dynamic_cast<SudokuSolver_SequentialDLX*>(solver.get());
child_solver->solve();
}
else if (mode == MODES::PARALLEL_DANCINGLINKS)
{
int NUM_THREADS = (argc >= 5) ? std::stoi(argv[4]) : 2;
omp_set_num_threads(NUM_THREADS);
#pragma omp parallel
{
#pragma omp single
{
solver = std::make_unique<SudokuSolver_ParallelDLX>(board);
SudokuSolver_ParallelDLX* child_solver = dynamic_cast<SudokuSolver_ParallelDLX*>(solver.get());
child_solver->solve();
}
}
}
Я обнаружил, что это своего рода дубликаты кода, поэтому я хочу шаблонизировать их примерно так:
template <typename T>
void downCastandSolve(std::unique_ptr<SudokuSolver> solver, SudokuBoardamp; board)
{
solver = std::make_unique<T>(board);
T* child_solver = dynamic_cast<T*>(solver.get());
child_solver->solve();
}
Однако я получил следующее сообщение об ошибке:
error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>amp;) [with _Tp = SudokuSolver; _Dp = std::default_delete<SudokuSolver>]’
Не уверен, как правильно шаблонизировать части кода. Надеюсь, кто-нибудь сможет помочь!
Комментарии:
1. Похоже, вы могли бы заменить необходимость
dynamic_cast
в том, чтобы сделатьsolve
функцию виртуальной… Кроме того, кажется, чтоstd::unique_ptr<SudokuSolver> solver
это не очень полезно, так как оно никогда не используется и только усложняет оставшийся код, добавляя дополнительные приведения…2.
solver
Привыкает ли он после этого ветвящегося кода? Потому что, как говорит @Phil1970, код без него очень прост:T(board).solve();
3. @Phil1970 @Бен Фойгт Да,
solver
используется после кода ветвления для доступа к решению, хранящемуся вSudokuSolver
классеsolver->get_solution()
. Вот почему мне нужно здесь успокоиться. Но я надеюсь, что есть лучшее предложение для моего дизайна…4. Очевидно
auto child_solver = std::make_unique<T>(board); child_solver->solve(); solver = std::move(child_solver);
, что это позволит избежать бесполезного актерского состава без каких-либо других изменений. `5. Параллельный код также кажется подозрительным, поскольку нет цикла или способа объединения результатов…
Ответ №1:
У вас был бы гораздо более четкий код, если solve
бы функция была виртуальной.
Кроме того, либо конструктор, либо метод решения должны получать ссылку на плату, но не оба. Наличие единого способа упрощает понимание кода, поскольку каждый алгоритм работает одинаково.
std::unique_ptr<SudokuSolver> CreateSolver(MODES mode)
{
switch (mode)
{
case MODES::SEQUENTIAL_BACKTRACKING:
return std::make_unique<SudokuSolver_SequentialBacktracking>();
...
}
}
Затем, предполагая solve
, что он виртуальный, код возобновляется до:
auto solver = CreateSolver(mode);
solver->solve(board);
solver->get_solution();
Любые параллельные элементы должны быть скрыты внутри solve
функции, когда это необходимо.
При написании такого кода его гораздо легче читать, и вам не нужна дополнительная функция шаблона для совместного использования кода, поскольку вы с самого начала избегаете дублирования.
Комментарии:
1. Большое вам спасибо за ваши предложения. Это действительно значительно облегчает чтение и понимание моего кода. 🙂
2. @hmhuang Совершенно нормально изменить принятый ответ, если это помогло вам даже больше, чем мой ответ. Я тоже поддержал это решение 🙂
Ответ №2:
std::unique_ptr
s не подлежат копированию. Вам нужно взять его по ссылке:
void downCastandSolve(std::unique_ptr<SudokuSolver>amp; solver, SudokuBoardamp; board)
// ^