我(可能)有一个简单的问题。 我何时必须声明模板中使用的函数? 打印出以下代码(使用gcc> = 4.1):
初始化我的A对象
没有init
使用gcc 4.0打印出以下代码:
初始化我的A对象
初始化我的字符串对象
#include <iostream>
#include <string>
template<typename T>
void init(T& t){
std::cout << "no init" << std::endl;
}
// void init(std::string& t);
template <typename T>
void doSomething(T& t){
init(t);
// do some further stuff
}
void init(std::string& t){
std::cout << "init my string object" << std::endl;
}
class A{
};
void init(A& t){
std::cout << "init my A object" << std::endl;
}
int main(){
A a;
doSomething(a);
std::string s("test");
doSomething(s);
return 0;
}
std :: string和A的用法有什么区别? 不应该有相同的行为吗?
通过额外的前向声明,它可以正常工作, 但我什么时候需要呢?
干杯, CSpille
答案 0 :(得分:4)
仅使用参数依赖查找(查找与函数参数关联的名称空间中的函数)查找实例化点处的函数。正常查找仅在模板定义时完成。
因此对于std::string
,只有通用的init
函数模板是可见的并且被调用,因为在命名空间std
中没有特定的模板。对于A
,在A
的全局命名空间中找到了更具体的函数。
如果转发声明字符串特定函数出现在doSomething
之前,则正常的非限定查找会在定义中找到它并稍后使用它。
如果您按如下方式调用init
,则会禁止参数依赖查找,因此也会使用A
的通用模板。
template <typename T>
void doSomething(T& t){
(init)(t);
// won't do ADL
}
(作为一个侧节点:在这种情况下,不仅在实例化时禁止参数依赖查找,而且init
首先不会是依赖名称 - 只有非括号和非限定函数名称因此,只有在定义时才进行非ADL查找,并且在实例化时不会进行任何查找,即使存在与ADL不同的形式也是如此。)