【问题标题】:Variadic template, no matching function for call可变参数模板,调用没有匹配函数
【发布时间】:2018-07-02 11:52:46
【问题描述】:

我正在尝试使用可变参数模板来重构我的一些代码,但编译器出现“没有匹配的调用函数”错误。下面是一个简化的版本(它可能对功能没有意义,但是一个重现错误的例子):

// base case
void testFunc(int i) { std::cout << i << std::endl; }

template <class T, class... Args> void testFunc(int i) {
  T t = 0;
  std::cout << t << std::endl;
  testFunc<Args...>(i);
}

int main() {
  testFunc<int, long, float>(1);
  return 0;
}

错误信息:

main.cpp:9:3: error: no matching function for call to 'testFunc'
  testFunc<Args...>(i);
  ^~~~~~~~~~~~~~~~~
main.cpp:9:3: note: in instantiation of function template specialization 'testFunc<float>' requested here
main.cpp:9:3: note: in instantiation of function template specialization 'testFunc<long, float>' requested here
main.cpp:13:3: note: in instantiation of function template specialization 'testFunc<int, long, float>' requested here
  testFunc<int, long, float>(1);
  ^
main.cpp:6:40: note: candidate template ignored: couldn't infer template argument 'T'
template <class T, class... Args> void testFunc(int i) {
                                       ^
1 error generated.

看起来模板参数的展开是有效的,并在基本情况下停止。但我已经定义了基本情况。为什么没有匹配功能?

【问题讨论】:

    标签: c++ c++11 templates variadic-templates template-argument-deduction


    【解决方案1】:

    问题是调用

    testFunc<Args...>(i);
    

    您调用testFunc() 的模板版本,而不是基本案例版本。

    Args... 为空时,没有可用的模板版本。

    为了解决这个问题...如果你可以使用C++17,你可以使用if constexpr,正如YSC所建议的那样。

    对于 C++11 和 C++14,我建议使用 struct 的模板部分特化。

    以下是一个完整的工作示例

    #include <iostream>
    
    // base case  
    template <typename...>
    struct foo
     { static void bar (int i) { std::cout << i << std::endl; } };
    
    // recursive case
    template <typename T, typename ... Args>
    struct foo<T, Args...>
     {
       static void bar (int i)
        {
          std::cout << T{} << std::endl;
    
          foo<Args...>::bar(i);
        }
     };
    
    int main()
     {
       foo<int, long, float>::bar(1);
     }
    

    【讨论】:

      【解决方案2】:

      对于单一类型,您的函数定义不明确,因为它尝试调用与 void testFunc(int i) 不同的 void testFunct&lt;&gt;(int)

      您可以在使用 C++17 的 constexp if 递归之前测试参数包的大小:

      template <class T, class... Args> void testFunc(int i) {
        T t = 0;
        std::cout << t << std::endl;
        if constexpr (sizeof...(Args) > 0) {
          testFunc<Args...>(i);
        } else {
          testFunc(i);
        }
      }
      

      【讨论】:

      • 不错,但是恕我直言,您应该指定 if constexpr 从 C++17 开始可用
      • @max66 你的回答做到了。我认为我们一起提供了一套很好的补充答案。我很好。
      • 好吧...我看到的问题是读者只阅读您的解决方案;无论如何,您还应该添加称为 testFunc(i) 的 else 案例(基础,无模板,案例),否则您的代码不会打印 i 值。
      • @max66 正确,已修复
      • “C++ 之旅”“5.6. 可变参数模板”中的代码不起作用。感谢您的解决方案。
      【解决方案3】:

      如前所述,问题来自testFunc&lt;int&gt;(int i) 试图调用testFunct&lt;&gt;(int t)

      但是在 C++ 中 testFunct&lt;&gt;(int t)testFunct(int t) 不同

      另请注意,在 C++ 中,您可以部分专门化 函数,例如 here 中的说明。

      一种与您的方法接近的解决方案是定义

      // Stop recursion
      template <class T>
      void testFunc(int i)
      {
        T t = 0;
        std::cout << t << " " << typeid(T).name() << std::endl;
      }
      

      感谢SFINAE,避免模糊定义

      // instantiated only when Args... is not "empty"
      template <class T, class... Args>
      typename std::enable_if<sizeof...(Args)>::type testFunc(int i)
      {
        T t = 0;
        std::cout << t << " " << typeid(T).name() << std::endl;
        testFunc<Args...>(i);
      }
      

      这是完全合法的 C++11,它非常符合您最初的猜测


      完整运行代码:g++ -std=c++11 testVariadic.cpp; ./a.out编译

      #include <iostream>
      #include <type_traits>
      
      template <class T>
      void testFunc(int i)
      {
        T t = 0;
        std::cout << t << " " << typeid(T).name() << std::endl;
      }
      
      template <class T, class... Args>
      typename std::enable_if<sizeof...(Args)>::type testFunc(int i)
      {
        T t = 0;
        std::cout << t << " " << typeid(T).name() << std::endl;
        testFunc<Args...>(i);
      }
      
      int main()
      {
        testFunc<int, long, float>(1);
        return 0;
      }
      

      输出:

      0 i
      0 l
      0 f
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-28
        • 2023-03-07
        • 1970-01-01
        • 2017-03-26
        相关资源
        最近更新 更多