我有一个类,在代码剪辑中我把它的部分贴在我认为问题所在的地方。
class SubtreeExplorer : public AbstractTask {
public:
SubtreeExplorer(Threadpool& tp, SudokuBoard&& sudoku)
: tp(tp), sudoku(std::move(sudoku)) {}
...
private:
Threadpool& tp;
SudokuBoard sudoku;
bool sudoku_backtracking_search(SudokuBoard& s) {
...
while(...){
...
// let another thread explore the subtree
tp.submit(make_shared<SubtreeExplorer>(tp, SudokuBoard(sudoku)));
}
}
};
当我尝试编译它时,它给出了一个错误:
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/memory:4325:5: error: static_assert failed due to requirement 'is_constructible<SubtreeExplorer,
Threadpool &, SudokuBoard &>::value' "Can't construct object in make_shared"
static_assert( is_constructible<_Tp, _Args...>::value, "Can't construct object in make_shared" );
我使用的是VS代码,在IDE中没有突出显示错误。 这个问题很可能是由make_shared
引起的,但是我不能确定构造函数中的内容(SubtreeExplorer类)。
SudokuBoard(sudoku)
从给定的棋盘返回一个新的棋盘,只需进行少量修改。 我想把这个新板移动到新的子树资源管理器中。
在谷歌上,我写的构造函数应该把板子移到里面,但我还是收到了我写的编译错误,还有一长串难以阅读的注释:
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/memory:2259:9: note: in instantiation of function template specialization
'std::__1::__compressed_pair_elem<SubtreeExplorer, 1, false>::__compressed_pair_elem<Threadpool &, SudokuBoard &, 0, 1>' requested here
_Base2(__pc, _VSTD::move(__second_args),
^ /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/memory:3672:16: note: in instantiation of function template specialization
'std::__1::__compressed_pair<std::__1::allocator<SubtreeExplorer>, SubtreeExplorer>::__compressed_pair<std::__1::allocator<SubtreeExplorer> &,
Threadpool &, SudokuBoard &>' requested here
: __data_(piecewise_construct, _VSTD::forward_as_tuple(__a),
^ /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/memory:4331:26: note: in instantiation of function template specialization
'std::__1::__shared_ptr_emplace<SubtreeExplorer, std::__1::allocator<SubtreeExplorer>
>::__shared_ptr_emplace<Threadpool &, SudokuBoard &>' requested
here
::new(__hold2.get()) _CntrlBlk(__a2, _VSTD::forward<_Args>(__args)...);
^ /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/memory:4710:29: note: in instantiation of function template specialization
'std::__1::shared_ptr<SubtreeExplorer>::make_shared<Threadpool &, SudokuBoard &>' requested here
return shared_ptr<_Tp>::make_shared(_VSTD::forward<_Args>(__args)...);
^ src/sudoku_parallel.cpp:119:13: note: in instantiation of function template specialization 'std::__1::make_shared<SubtreeExplorer, Threadpool &, SudokuBoard
&>' requested here tp.submit(make_shared<SubtreeExplorer>(tp, sudoku));
^ src/sudoku_parallel.cpp:41:3: note: candidate constructor not viable: no known conversion from 'SudokuBoard' to 'SudokuBoard &&' for 2nd argument SubtreeExplorer(Threadpool& tp, SudokuBoard&& sudoku) ^ src/sudoku_parallel.cpp:39:7: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 2 were provided class SubtreeExplorer : public AbstractTask {
^ src/sudoku_parallel.cpp:39:7: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 2 were provided
这让我产生了这样的想法:我向构造函数传递了错误数量的参数,尽管它需要两个参数,而我传递了这两个参数,一个线程池和一个数独板。
基本上,SubtreeExplorer是在sudoku_backtracking_search函数的主体中创建的:
int main() {
...
SubokuBoard sudoku(filepath);
tp.submit(make_shared<SubtreeExplorer>(tp, sudoku));
...
}
编辑:tp是一个线程池,它的submit方法具有以下签名:
bool submit(std::shared_ptr<AbstractTask> task);
而AbstractTask类如下所示:
struct AbstractTask {
virtual ~AbstractTask() = default;
virtual void run() = 0;
};
构造函数接受对SudokuBoard
的rvalue引用,但您传递给它的是lvalue。 这就是为什么会出现错误; lvalue引用不能隐式转换为rvalue引用,因此调用失败。
您可以使用以下任一选项更正此问题:
>
最好的选择是将SubtreeExplorer
构造函数更改为按值接受第二个参数,这允许调用方根据是否需要保留参数的副本来移动构造或复制构造它。 当您需要移动语义时,您可以从中获益,但副本仍然是可以接受的。
(这假设SudokuBoard
类型具有复制构造函数。)
SubtreeExplorer(Threadpool& tp, SudokuBoard sudoku)
: tp(tp), sudoku(std::move(sudoku)) {}
通过应用std::move()
:
SubokuBoard sudoku(filepath);
tp.submit(make_shared<SubtreeExplorer>(tp, std::move(sudoku)));
完全移除命名变量,并传递一个临时的:
tp.submit(make_shared<SubtreeExplorer>(tp, SudokuBoard{filepath}));
我建议实现选项1,但如果在此make_shared
调用之后不需要使用sudoku
变量,那么也可以实现选项2或选项3--否则您将创建一个毫无意义的复制。