在这种情况下模板参数推导是如何工作的
How does template argument deduction work in this case?
给定这段代码,模板参数推导如何决定对最后一个函数调用做什么?
#include <iostream>
template<typename Ret, typename... Args>
Ret foo(Args&&...) {
std::cout << "not voidn";
return {};
}
template<typename... Args>
void foo(Args&&...) {
std::cout << "voidn";
}
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
参数的两个参数。
(4)似乎模棱两可。它显式地指定了一个模板实参,就像(2)和(3)一样。模板实参匹配实参,就像(2)一样。但是,它不使用模板实参作为第一个实参并推导出其他两个实参,而是使用显式模板实参作为返回类型并推导出所有三个Args
实参。
为什么(4)似乎一半遵循(2),但又使用另一个版本?我最好的猜测是,要填写的单个模板参数比只填写参数包更匹配。标准在哪里定义了这种行为?
这是使用GCC 4.8.0编译的。为方便起见,下面是在Coliru上运行的一个测试。
然而,在Clang 3.1中,由于歧义(见注释),(4)不能编译。这就有可能导致这两个编译器中的一个存在bug。使这种可能性更有可能的是,Visual Studio 2012 11月CTP编译器给出了与Clang相同的结果,其中(4)是模糊的。我相信Clang是正确的(仍然在3.3 SVN中),(4)中的调用根据偏排序规则是模糊的-两个函数模板都是可行的,都不比更专门化。
注意,GCC可以通过将可变包转换为单个参数来强制提供相同的输出:
#include <iostream>
template<typename Ret, typename T>
Ret foo(T&&) {
std::cout << "not voidn";
return {};
}
template<typename T>
void foo(T&&) {
std::cout << "voidn";
}
int main() {
foo<int>(3);
}
输出:main.cpp: In function 'int main()': main.cpp:15:15: error: call of overloaded 'foo(int)' is ambiguous
生活例子。
相关文章:
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 链表c++插入,所有情况都已检查,但没有任何工作
- 当 int 方法工作正常时,void 方法有何不同,或者为什么我不能调用 void 方法?