Variadic 模板,没有匹配的调用函数

Variadic template, no matching function for call

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

// 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.

看起来模板参数的解包工作正常,并在基本情况下停止。但我已经定义了基本情况。为什么没有匹配功能?

对于单一类型,您的函数定义不明确,因为它试图调用不同于 void testFunc(int i).

void testFunct<>(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);
  }
}

问题是调用

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);
 }

如前所述,问题来自于 testFunc<int>(int i) 试图调用 testFunct<>(int t)

但是在 C++ 中 testFunct<>(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