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
我正在尝试使用可变参数模板来重构我的一些代码,但编译器出现 "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