【发布时间】:2023-03-29 06:28:02
【问题描述】:
在 C++ 模板函数 foo() 中,调用 ::bar(TT*) 在 gcc 4.4.3 下会出现以下错误:
g++ -o hello.o -c -g hello.cpp
hello.cpp: In function 'void foo(std::vector<TT*, std::allocator<TT*> >&)':
hello.cpp:8: error: '::bar' has not been declared
这是有问题的代码:
// hello.cpp
#include <vector>
template<typename TT> void foo(std::vector<TT*> &vec)
{
TT *tt;
::bar(tt);
vec.push_back(tt);
}
class Blah
{
};
void bar(Blah *&)
{
}
int main(int argc, char *argv[])
{
std::vector<Blah*> vec;
foo(vec);
return 0;
}
C++ 区分依赖于模板参数(此处为 TT)的符号和那些独立且可以立即求值的符号。
显然,编译器认为我的 ::bar(TT*) 调用是独立的,并尝试立即解决它。同样清楚的是,该函数调用 依赖于 TT,因为该函数调用采用 TT* 类型的参数,因此编译器应该等到 foo(vec) 实例化才能解析 ::bar(TT* )。
这是一个 gcc 错误还是我错过了 C++ 模板的一些微妙之处?
编辑:这里有一个稍微复杂一点的例子,有两个版本的 ::bar() 来澄清声明顺序不是我的问题的问题。解析模板时,编译器无法知道下面的 main() 是用 TT=Blah 还是用 TT=Argh 实例化模板函数。因此,编译器最早应该在 line 35 line 28 之前(如果有的话)给出错误。但是 line 8 line 16 给出了错误。
编辑#2:改进了这个例子。
编辑#3:添加了对这个示例的更正以使其按需要工作。 bar(tt) 现在正确地引用 bar(Blah*)。理由如下。 (谢谢大家)。
// hello.cpp
#include <vector>
class XX {};
void bar(XX*) {}
class CC {
public:
void bar();
void bar(int *);
void bar(float *);
template<typename TT> static void foo(std::vector<TT*> &vec);
};
template<typename TT>
void CC::foo(std::vector<TT*> &vec) {
using ::bar;
TT *tt;
bar(tt);
vec.push_back(tt);
}
class Argh {};
void bar(Argh *&aa) { aa = new Argh; }
class Blah {};
void bar(Blah *&bb) { bb = new Blah; }
int main(int argc, char *argv[]) {
std::vector<Blah*> vec;
CC::foo(vec);
return 0;
}
【问题讨论】:
-
错误说“::bar”没有声明不是像“没有匹配的原型”......也许bar真的没有声明?这是一个猜测
-
"同样清楚的是,该函数调用依赖于 TT,因为该函数调用采用 TT* 类型的参数,因此编译器应该等到 foo(vec) 实例化才能解析 ::bar( TT*)。”。错误的。仅仅是名称“::bar”和“bar”是不相关的。有一个特殊规则可以使其他非依赖名称在用作函数时依赖,这是 @Chris 引用的文本,并且仅适用于非限定名称。无论如何,在实例化时需要做的是使用给定(依赖)参数对找到的声明进行重载决议。
-
我已经在下面提到了这一点,但这似乎不同意你的观点:Stroustrup TC++PL Sp Ed,第 C.13.8.1 节,从属名称:“基本上,调用的函数的名称是如果通过查看它的参数或它的形式参数,它显然是依赖的”。按照这个标准,
::bar“明显依赖”。
标签: c++