鉴于此代码,模板参数推导如何决定最后一次函数调用?
#include <iostream>
template<typename Ret, typename... Args>
Ret foo(Args&&...) {
std::cout << "not void\n";
return {};
}
template<typename... Args>
void foo(Args&&...) {
std::cout << "void\n";
}
int main() {
foo(3, 'a', 5.4); //(1): prints "void"
foo<int, char>(3, 'a', 5.4); //(2): prints "void"
foo<int>('a', 5.4); //(3): prints "not void"
foo<int>(3, 'a', 5.4); //(4): prints "not void"
}
(1)似乎很简单。它不能推断出返回类型,因此使用了void
版本。
(2)明确陈述了一些参数的类型。第一个模板参数匹配第一个参数,第二个模板参数匹配第二个参数,推导出第三个模板参数。如果int
用于返回类型,则char
将与第一个参数不匹配。
(3)与(2)的作用相同,但第一种类型不匹配。因此,必须将其推断为返回类型和用于推导两个Args
参数的两个参数。
Args
参数。
为什么(4)似乎有一半跟随(2),但是然后使用其他版本?我最好的猜测是填充的单个模板参数是一个比参数包更好的匹配。标准在哪里定义了这种行为?
这是使用GCC 4.8.0编译的。为方便起见,这是test run上的Coliru。
但是,在Clang 3.1中,由于含糊不清(见注释),(4)无法编译。这开启了这两个编译器中的一个有错误的可能性。使这种可能性更可能的是,Visual Studio 2012 November CTP编译器提供与Clang相同的结果,(4)模糊不清。
答案 0 :(得分:4)
我认为Clang是正确的(仍然在3.3 SVN中),根据部分排序规则,(4)中的调用是不明确的 - 两个函数模板都是可行的,并且更专业
请注意,可以通过将可变参数包转换为单个参数来强制GCC提供相同的输出:
#include <iostream>
template<typename Ret, typename T>
Ret foo(T&&) {
std::cout << "not void\n";
return {};
}
template<typename T>
void foo(T&&) {
std::cout << "void\n";
}
int main() {
foo<int>(3);
}
输出:
main.cpp: In function 'int main()': main.cpp:15:15: error: call of overloaded 'foo(int)' is ambiguous