我何时必须声明模板中使用的函数?

时间:2010-07-05 09:40:18

标签: c++ templates forward-declaration

我(可能)有一个简单的问题。 我何时必须声明模板中使用的函数? 打印出以下代码(使用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

1 个答案:

答案 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不同的形式也是如此。)