我有这样的代码:
template<class ListItem>
static void printList(QList<ListItem>* list)
{
for (auto i = list->size() - 1, j = -1; i >= 0; --i) {
std::cout << i << ", " << j << ": " << list->at(i) << std::endl;
}
}当我用g++ 6.2.1编译它时,我得到以下编译器输出:
test.cpp: In function ‘void printList(QList<T>*)’:
test.cpp:10:7: error: inconsistent deduction for ‘auto’: ‘auto’ and then ‘int’
for (auto i = list->size() - 1, j = -1; i >= 0; --i) {
^~~~我理解这一点,如果变量有不同的类型,如auto i = 0.0, j = 0;,但在本例中,list是指向QList的指针,它的size()方法返回int,-1本身也应该是int。错误信息也有点奇怪。
变量i和j只需要在这个循环中使用,我想将它们声明为循环参数。输入int而不是auto并不难,但我想知道:auto不应该用于一次声明多个变量,还是这里遗漏了什么,它确实是错误的代码,或者可能是编译器的错误?
看起来,使用模板函数是这里的关键部分,将循环从模板中分解不会产生错误。所以,更像是编译器中的一个bug?
发布于 2016-12-06 10:56:50
这是GCC的一个错误。
根据dcl.spec.auto/1:
auto和decltype(auto)类型-specifiers用于指定占位符类型,该占位符类型稍后将被从初始化器中扣除。..。
模板参数演绎规则从不推断类型为auto。在这种情况下,推导的目的实际上是用推导的类型代替auto。
在这个示例中,list有一个依赖类型(它依赖于模板参数ListItem),因此表达式list->size() - 1也有一个依赖类型,这使得i的类型也是依赖的,这意味着只有在函数模板printList的实例化之后才能解析它。只有这样,才能检查与该声明相关的其他语义约束。
根据tem.res/8:
知道哪些名称是类型名称允许检查每个模板的语法。该程序格式不正确,不需要诊断,如果: ..。一长串不适用于此的案件. 否则,不应对可以为其生成有效的专门化的模板()发出诊断。注意:如果模板被实例化,将根据本标准中的其他规则诊断错误。准确地诊断这些错误的时间是实现质量的问题。-尾注
(强调地雷)
GCC在分析模板printList的定义时发出该错误是错误的,因为可以生成明显有效的模板专门化。实际上,如果QList没有任何专门化,而size()返回的不是int,那么i和j的声明在printList的所有实例化中都是有效的。
所有引号都来自N4606,这是(几乎)当前的工作草案,但自C++14以来,上述引号的相关部分并没有改变。
更新: GCC 6/ 7版的确认为回归。感谢T.C.的错误报告。
更新:最初的bug (78693)是为即将发布的6.4和7.0版本修复的。它还揭示了GCC处理此类结构的其他一些问题,从而产生了另外两个bug报告:79009和79013。
发布于 2016-11-28 19:32:37
然后我将总结所收到的关于这个主题的信息。
示例代码中的问题是如何使用模板函数。编译器首先在不实例化模板的情况下对模板进行泛型检查,这意味着类型(即模板参数(以及依赖于它们的类型,就像其他模板一样)是未知的),如果依赖于这些未知类型,auto将再次推导为auto (或不推导为某些具体类型)。在我看来,即使在扣除之后,auto仍然可以是auto。现在,原始的编译器错误文本是完全有意义的:变量j被推断为int类型,但是变量i经过推导后仍然是auto。因为auto和int是不同的类型,所以编译器会生成错误。
https://stackoverflow.com/questions/40841777
复制相似问题