代码之家  ›  专栏  ›  技术社区  ›  Mathieu Rodic

调用时模板参数推导/替换失败

  •  1
  • Mathieu Rodic  · 技术社区  · 2 周前

    要么是我对C++的理解有问题,要么是某个地方有一个隐藏的拼写错误。。。我在那几个LOCA上浪费了几个小时。

    首先,我定义了 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);
    

    谢谢你们,隔离一个最小的例子真的帮了我调试!

    1 回复  |  直到 2 周前
        1
  •  2
  •   n. m. could be an AI    2 周前
    whatever_t start(std::function<FunctionResult(const bool&, FunctionArgs...)> function, 
              FunctionArgs... args) 
    

    这有两个原因 FunctionArgs... 。当的一部分 std::function 类型,上下文是不可推导的,并且包将从 std::函数 在另一种情况下,上下文是可推导的,因此包将从实际的函数参数中推导出来。

    这两包应该是 完全一样 在这两种情况下。然而 FunctionArgs... args 永远不会推导引用类型,并且您的函数接受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 子句或旧的SFINAEor只需调用它,如果无法进行调用,则处理帮助较小的错误消息),