要么是我对 C++ 的理解有问题,要么是某个地方存在隐藏的拼写错误...我在这几个 LOC 上浪费了几个小时。
首先,我定义了一个
start()
方法:
template <typename FunctionResult, typename ...FunctionArgs>
inline std::shared_ptr<StoppableThread> start(
std::function<FunctionResult(const bool&, FunctionArgs...)> function, FunctionArgs... args)
{ ... }
还有一些
threadedSearch()
lambda 函数:
std::function<void(const bool&,
const Source&, Population&,
const std::vector<Parameter>&,
const size_t&, const size_t&)> threadedSearch = ... ;
但是当我尝试执行此操作时:
Source source = { ... };
Population population = { ... };
const std::vector<Parameter> variationsParameters = { ... };
const size_t randomCandidatesCount = ..., lineageCount = ...;
auto searchThread = start(
threadedSearch,
source, population,
variationsParameters,
randomCandidatesCount, lineageCount);
编译器不同意后者对
starŧ()
的调用,并告诉我:
# with g++
error: no matching function for call to
‘start(std::function<void(const bool&, const Source&, Population&, const std::vector<Parameter>&, const long unsigned int&, const long unsigned int&)>&,
Source&, Population&, const std::vector<Parameter>&, const size_t&, const size_t&)’
[...]
note: candidate: ‘template<class FunctionResult, class ... FunctionArgs> std::shared_ptr<StoppableThread>
start(std::function<FunctionResult(const bool&, FunctionArgs ...)>, FunctionArgs ...)
note: template argument deduction/substitution failed:
note: inconsistent parameter pack deduction with ‘const Source&’ and ‘Source’
# with clang++
error: no matching member function for call to 'start'
note: candidate template ignored: deduced conflicting types for parameter 'FunctionArgs'
(<const Source&, Population&, const std::vector<Parameter>&, const unsigned long&, const unsigned long&>
vs.
<Source, Population, std::vector<Parameter>, size_t, size_t>)
我的问题是:WTF?
还有:我能做什么?在
start<...>()
调用中显式指定模板参数甚至不起作用...
我不知道如何让编译器理解它应该看到的“真实”参数类型......
可以在这里找到完全崩溃的最小示例:https://onlinegdb.com/FtBIGmkH-
好的,用它来编译:
auto searchThread = start<void, const Source&, Population&, const std::vector<Parameter>&, const size_t&, const size_t&>(
threadedSearch,
source, population,
parameters,
randomCandidatesCount, lineageCount);
谢谢你们,隔离一个最小的示例确实帮助我进行了调试!
whatever_t start(std::function<FunctionResult(const bool&, FunctionArgs...)> function,
FunctionArgs... args)
这出现了两次
FunctionArgs...
。当属于 std::function
类型的一部分时,上下文是不可推导的,并且包将按原样从 std::function
中获取。在另一种情况下,上下文是可推导的,因此包将从实际的函数参数中推导出来。
在两种情况下,两个包都应该完全相同。然而
FunctionArgs... args
永远不会推导出引用类型,并且你的函数接受 const 引用。因此,一个包将充满 const 引用类型,而另一个包将充满非引用类型。这是替换失败。
解决该问题的一种方法是使其他事件也不可推论。
whatever_t start(std::function<FunctionResult(const bool&, FunctionArgs...)> function,
std::type_identity_t<FunctionArgs>... args)
将完成这项工作(需要 C++20,但可以在紧要关头实现相当于
std::type_identity_t
的功能)。
另一种方法是将函数类型与参数解耦。
template<typename Func, typename ... Args>
whatever_t start(Func&& func, Args&& ... args)
(为了确保可以使用
func
调用 args
,您可以使用 requires
子句或老式的 SFINAE,或者直接调用它,并在无法调用时处理不太有用的错误消息),