为什么在没有前向声明的情况下调用函数模板? [英] Why can I call function templates without forward declarations?

查看:145
本文介绍了为什么在没有前向声明的情况下调用函数模板?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果普通函数调用了尚未声明的函数,则会出现编译时错误:

If a normal function calls a function that has not been declared yet, I get a compile-time error:

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);
}

解决方法是前向声明被调用的函数,或者切换定义的顺序.

The fix is to either forward-declare the called function, or to switch the order of definitions.

但是,对于功能模板,似乎不需要这些修补程序:

However, these fixes do not seem to be necessary with function templates:

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);
}

这样编译就可以了.这是为什么?当编译器看到bar(x)时,为什么没有抱怨?

This compiles just fine. Why is that? When the compiler sees bar(x), why does it not complain?

(我正在使用g ++ 4.6.3)

(I am using g++ 4.6.3)

推荐答案

这是为什么天空是用砖砌成的"类型的问题.即,一个问题,为什么某些错误是真实的.并非在C ++中您的代码是合法的.

This is a "why is the sky made out of bricks" type question. Ie, a question that asks why something false is true. It is not the case that in C++ your code is legal.

实时示例,如您在gcc 4.8中所见,它实际上并不能编译.

Live example, as you can see in gcc 4.8 this does not actually compile.

我猜想为什么gcc 4.6为什么要让此代码编译"这个问题仍然存在.编写template扩展器时,编译器早期做的一件事就是将它们视为类似于宏的东西.在声明它们的地方几乎不会做任何事情,而在实例化它们时将查找所有内容.

I guess the question "why does gcc 4.6 let this code compile" remains. One of the things that compilers did early on when writing template expanders was to treat them as something similar to macros. Very little would be done when they where declared, and everything would be looked up when they where instantiated.

现在,在声明template时,编译器往往会做更多的事情,而在实例化时,它会做的更少.这是C ++标准所要求的,或者至少是更接近的.

Compilers now tend to do more thing when the template is declared, and less when it is instantiated. This is what the C++ standard requires, or is at least closer.

发生这种情况时,ADL可以解决此问题:通过ADL查找bar的查找不必在编写foo时可见,而在实例化时可见.

As it happens, ADL can get around this: bar lookups that find bar via ADL do not have to be visible at the point where foo is written, but rather at the point of instantiation.

gcc 4.8错误消息很容易解释:

The gcc 4.8 error message is pretty self explanatory:

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)
      ^

这些要求可能已在C ++ 11中进行了更改或阐明,因此在C ++ 03标准下gcc 4.6的行为可能是合法的.

these requirements may have been changed or clarified in C++11, so it is possible that gcc 4.6's behavior was legal under the C++03 standard.

这篇关于为什么在没有前向声明的情况下调用函数模板?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆