我有以下代码:
#include <iostream>
template <typename... Args>
void f(int a, int b, Args... args) {
std::cout << b << '\n';
f(a, args...);
}
void f(int, int b) {
std::cout << b << '\n';
}
int main() {
f(1, 2);
//f(1, 2, 3);
}
虽然f(1, 2)
编译,但f(1, 2, 3)
却没有。从编译器生成的错误消息中,我看到f<>
正在以某种方式实例化。在实例化中,调用f(a)
,从而产生错误。是什么让编译器不使用f(int, int)
但尝试在解析调用f<>(int, int)
的过程中实例化f(1, 2, 3)
?
答案 0 :(得分:3)
在可变参数函数模板f()
中,由于[temp.dep],递归调用中的f
是一个依赖名称,强调我的:
在表达中 形式:
postfix-expression ( expression-listopt)
postfix-expression 是 unqualified-id , unqualified-id 表示依赖名称,如果
(1.1) - 表达式列表中的任何表达式都是包扩展(14.5.3),
而且,根据[temp.dep.res],强调我的:
在解析依赖名称时,会考虑以下来源的名称:
(1.1) - 在模板的定义处可见的声明 (1.2) - 来自名称空间的声明与函数参数的类型相关联 实例化上下文(14.6.4.1)和定义上下文。
只有一个f
声明在template <typename... Args> void f(int, int, Args...)
的定义中可见,而这本身就是int
。第二点不适用于此,因为您的所有参数都是// this can be just the declaration
void f(int, int ) { /* ... */ }
template <typename... Args>
void f(int a, int b, Args... args)
{
std::cout << b << '\n';
f(a, args...); // now this will call f(int, int)
// if sizeof...(Args) == 1
}
,并且基本类型没有关联的命名空间。由于无法使用单个参数调用该函数模板,因此会出现编译错误。
解决方案是重构代码,以便在定义时可见基本情况,即:
#include <iostream>
template <typename A, typename... Args>
void f(A a, int b, Args... args) {
std::cout << b << '\n';
f(a, args...);
}
template <typename A>
void f(A a, int b) {
std::cout << b << '\n';
}
struct bar {};
int main() {
//f(1,2,3); // still doesn't compile, same reasoning
f(bar{}, 2, 3); // OK. bar is in the global namespace, so declarations
// from the global namespace in both instantiation
// and definition context are considered, which includes
// the second `f`.
}
(1.2)适用的例子如下:
<a href="http://mypage/comment/reply/NID#comment-form">Reply</a>