可变参数模板和类型推断问题
Variadic template and type deduction issue
在2012年ACCU C++ Pub测验的第15题中,我对结果感到困惑。
#include <iostream>
template<typename T> void P(T x) { std::cout << x; }
void foo(char a) { // foo 1
P(3);
P(a);
}
template <typename... A> // foo 2
void foo(int a, A... args) {
foo(args...);
P(a);
}
template <typename... A>
void foo(char a, A... args) { // foo 3
P(a);
foo(args...);
}
int main()
{
foo('1','2',48,'4','5');
}
我推断它会调用foo 3
、foo 3
、foo 2
、foo 3
、foo 1
,从而给出1243548
的输出。实际输出是12355248
,并在调试器中确认如下foo 3
、foo 3
、foo 2
、foo 2
、foo 1
。我无法弄清楚为什么第四次foo
电话会foo 2
不foo 3
.
作为参考,我使用 gcc 4.8.1 g++ -g -Wall -std=c++11 -Weffc++ -Wextra -O0 /tmp/foo.cpp -o /tmp/foo
编译,根本没有收到任何警告。
编辑:我刚刚在Visual Studio Express 2013上尝试过,它给出了1243548
,也没有警告。
这是GCC/VS中的编译器错误,还是规范中那些尴尬的未指定行为部分之一?
看起来这是声明的顺序。如果你在 foo 2 上方转发声明 foo 的相关重载,那么你将看到你预期的结果,即将这个放在 foo 2 之上:
template <typename... A>
void foo(char a, A... args);
该标准的相关部分在3.4.1.4中:
在任何函数、类或 用户声明的命名空间,应在全局使用之前声明 范围。
在 14.6.4.1 依赖名称解析中:
在解析从属名称时,来自以下源的名称是 考虑:
— 在定义点可见的声明 的模板。
— 来自与 实例化上下文中的函数参数的类型 (14.6.4.1)和定义上下文。
由于args
是依赖类型,因此名称解析仅将可见的名称视为模板的定义点。 foo 3
此时尚未声明,因此不能在过载解决中考虑。在此基础上,Visual Studio在允许使用foo 3
方面似乎是错误的。
foo 2
无法调用foo 3
foo 3
因为它不在foo 2
范围内。
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- C++LinkedList问题.数据类型之间存在冲突?没有匹配的构造函数
- 指针问题:从不兼容的类型"int"分配给"int *"
- 特征返回类型的 pybind11 问题
- 对齐C++字符串类型问题 std::字符串到 TStr
- C 中的类型问题
- dllimport类型问题
- 变量类型问题
- 并排定义指针和类型问题
- C++对数据类型问题
- B-树搜索引用子数据类型问题
- 协议缓冲区,让C#与C++对话:类型问题和模式问题
- 传递类成员函数:类型问题
- 使用受限函数时,尾随返回类型问题
- 如何正确使用模板?我在使用模板时遇到数据类型问题<>
- 链表输入类型问题
- 无序映射:自己的值类型问题
- 将windows c++项目链接到boost命令行体系结构类型问题
- 有数据类型问题的c++阶乘函数
- C++返回类型问题