模板功能和非模板功能调用顺序

时间:2012-08-29 09:13:04

标签: c++ linux templates

在Linux中我得到了

template max() is called

但是在Windows下我得到了

non-template max() is called

为什么呢?在Linux中,我使用gcc 4.5,在Windows中我使用VS2008。

#include <iostream>
#include <vector>

template < typename T > 
inline void max( const int& a, const T& b ) 
{
    std::cout << "template max() is called" << std::endl;
}

template < typename T > 
inline void Imax( const int& a, const std::vector<T>& b)
{
    max(a, b[0]);
}

inline void max( const int& a, const int& b ) 
{
    std::cout << "non-template max() is called" << std::endl;
}

int main()
{
    std::vector<int> v;
    v.push_back(1);
    Imax(1, v);       
    return 0;
}

2 个答案:

答案 0 :(得分:4)

在预标准C ++中,您可能会得到非模板max。 (没有标准,很难说你应该得到什么,但所有 我知道的预标准编译器会将名称查找推迟到 实例化。)从C ++ 89开始,你应该得到模板max;名称查找 发生在两个阶段:定义模板时(此时,仅限 模板max是可见的),并且在模板实例化时, 但在实例化点,仅针对依赖名称,仅使用 ADL。在您的代码中,max是一个从属名称,但是符号 触发ADL的是std::vector(其中包含std)和int 不添加任何东西,甚至不添加全局命名空间。所以 找不到非模板max

这些规则是C ++委员会最终正式确定的规则之一 编译器不能在一夜之间改变,所以实际上,如果 编译日期从1995年以前的任何时候开始,你可以期待 预标准行为。对于任何事情,我倾向于认为它 编译器错误,但......编译器必须支持现有代码,并且 理想情况下,以后的编译器可以选择使用以前的名称 查找规则。 (我说理想,因为有两套不相容的 名称查找规则显然是非平凡的。刚拿到一套 对于大多数编译器实现者来说,正确是很困难的。)

众所周知,微软的模板实现 即使在今天,也不符合标准。

答案 1 :(得分:2)

maxImax的调用取决于T,因此应在模板定义上下文(模板max为)中搜索max,并与实例化上下文中的参数相关查找相结合。 ADL不应找到空闲的最大值,因为int没有关联的命名空间。所以我的看法是gcc是正确的。

请注意,如果您有轻微变化:

#include <iostream>
#include <vector>

struct S {};

template < typename T > 
inline void max( const S& a, const T& b ) 
{
    std::cout << "template max() is called" << std::endl;
}

template < typename T > 
inline void Imax( const S& a, const std::vector<T>& b)
{
    max(a, b[0]);
}

inline void max( const S& a, const S& b ) 
{
    std::cout << "non-template max() is called" << std::endl;
}

int main()
{
    std::vector<S> v;
    v.push_back(S());
    Imax(S(), v);       
    return 0;
}

这里,全局命名空间与S相关联,因此在实例化时通过ADL查找找到非模板max。