【发布时间】:2015-01-26 12:17:51
【问题描述】:
当我尝试编译这段代码时
// void foobar(int);
template <class T>
struct Foo {
void bar(T t) { foobar(t); };
};
void foobar(int);
template class Foo<int>;
使用 g++ 4.8.2 我收到以下错误消息
foo.cc: In instantiation of ‘void Foo<T>::bar(T) [with T = int]’:
foo.cc:10:16: required from here
foo.cc:5:27: error: ‘foobar’ was not declared in this scope, and no
declarations were found by argument-dependent lookup at
the point of instantiation [-fpermissive]
void bar(T t) { foobar(t); };
^
foo.cc:8:6: note: ‘void foobar(int)’ declared here, later in the translation unit
void foobar(int);
^
(使用 clang 3.4 几乎相同)。
首先,我认为代码是正确的并且应该编译,因为 foobar 是模板声明中的一个依赖名称,并且应该只在模板实例化的第二阶段查找。当这在最后一行完成时,'foobar(int)' 已经被声明了。顺便说一句,当我取消最上面一行的注释时,代码会编译,但两个声明都在实例化之前,所以这无关紧要。
其次,错误信息本身对我来说似乎是矛盾的。它说“在实例化时没有找到声明”,即 foo.cc:10:16,它说它是在 foo.cc:8:6 处“稍后”声明的。对于我对数字和英语的所有了解,我将其称为“之前”而不是“之后”。
那么,这是 gcc 中的错误还是我做错了什么?由于这在我看来是一种常见的使用模式,但我不太相信。
顺便说一句:当我在 MSDN (http://msdn.microsoft.com/en-us/library/dx2zs2ee.aspx) 上使用 g++ 尝试“依赖类型的名称解析”的第二个示例时,结果与 vc++ 不同,后者(通常不是,但在这种特定情况下)会破坏这一点是 g++ 中的一个错误。
【问题讨论】:
-
好问题,我还有另一个问题,在某种意义上与你的相反:stackoverflow.com/questions/25188353/…
-
此页面未将函数调用列为有效的依赖类型或依赖表达式:en.cppreference.com/w/cpp/language/dependent_name
-
@didierc
foobar在这里是一个依赖名称,因为它是一个使用具有依赖类型的参数调用的函数(基本原理:在类型确定之前无法完成函数的重载解析) -
在 SO stackoverflow.com/questions/7369314/… 上找到了以下问题,根据接受的答案
class A{};void foobar(A);template class Foo<A>;应该编译,并且确实如此。似乎名称查找是不同的,因为搜索A的关联名称空间,但int没有关联名称空间作为基本类型。这有意义吗? -
@kevinarpe 你的意思是在错误输出中?它们来自 GCC,是 unicode 字符 \u2018 和 \u2019。相反,clang 使用普通的单引号 \u27。在 bash 中尝试
echo $'\x27\u2018\u2019'以查看它们。
标签: c++ templates language-lawyer argument-dependent-lookup