fre*_*low 4 c++ gcc templates function forward-declaration
如果普通函数调用尚未声明的函数,则会出现编译时错误:
void foo(int x)
{
bar(x); // ERROR: bar has not been declared yet
}
void bar(int x)
{
std::cout << x << '\n';
}
int main()
{
foo(42);
}
Run Code Online (Sandbox Code Playgroud)
修复方法是向前声明被调用的函数,或者切换定义的顺序.
但是,功能模板似乎不需要这些修复:
template<typename T>
void foo(T x)
{
bar(x); // OKAY
}
template<typename T>
void bar(T x)
{
std::cout << x << '\n';
}
int main()
{
foo(42);
}
Run Code Online (Sandbox Code Playgroud)
编译得很好.这是为什么?当编译器看到时bar(x),为什么不抱怨?
(我使用的是g ++ 4.6.3)
Yak*_*ont 10
这是一个"为什么用砖砌成的天空"式问题.即,一个问题,为什么一些错误是真的.事实并非如此,在C++中您的代码是合法的.
实例,正如您在gcc 4.8中看到的那样,实际上并没有编译.
我猜这个问题"为什么gcc 4.6让这个代码编译"仍然存在.编译器在编写template扩展器时早期做的事情之一是将它们视为与宏类似的东西.当声明它们时,它们会很少被完成,并且当它们被实例化时,所有内容都会被查找.
编译器现在倾向于在template声明时执行更多操作,而在实例化时则更少.这就是C++标准所要求的,或者至少更接近.
碰巧的是,ADL可以解决这个问题:通过ADL bar查找的查找bar不必在foo写入的位置可见,而是在实例化时.
gcc 4.8错误消息非常自我解释:
prog.cpp: In instantiation of ‘void foo(T) [with T = int]’:
prog.cpp:16:7: required from here
prog.cpp:6:10: error: ‘bar’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
bar(x); // OKAY
^
prog.cpp:10:6: note: ‘template<class T> void bar(T)’ declared here, later in the translation unit
void bar(T x)
^
Run Code Online (Sandbox Code Playgroud)
这些要求可能已在C++ 11中进行了更改或澄清,因此gcc 4.6的行为可能在C++ 03标准下是合法的.
当编译器第一次看到bar(x)它时,它不知道x类型,因此无法查找正确的类型bar.只有在实例化时foo,T因此x类型是已知的并且bar(x)可以被查找.
请注意,这仅适用于依赖表达式,即依赖于模板参数的表达式.如果添加bar(42),即使稍后将其实例化,也将无法编译T==int.
您可能还想谷歌"两阶段查找"以获取更多信息.只有最新版本的GCC才能正确实现这些规则,因为在解析模板的第一阶段还需要进行一些检查.作为Yakk的指针,较新版本的GCC会拒绝您的代码,因此请始终使用最新版本的GCC或Clang进行检查以确保安全.