2

在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;
}
4

2 回答 2

4

在准标准 C++ 中,您可能会得到 non-template max。(没有标准,很难说你应该得到什么,但我知道的所有准标准编译器都会将名称查找推迟到实例化。)从 C++89 开始,你应该得到 template max; 名称查找分两个阶段进行:定义模板时(此时,只有模板max可见),以及实例化模板时,但在实例化点,仅用于依赖名称,并且仅使用 ADL。在您的代码中,max是一个从属名称,但触发 ADL 的符号是std::vector(在 中绘制std)和int,它不会添加任何内容,甚至不会添加全局命名空间。max所以找不到非模板。

这些规则是 C++ 委员会最后正式制定的规则之一,编译器不可能在一夜之间改变,所以实际上,如果编译器的日期是 1995 年之前的任何时间,您可能会期待预标准行为。对于以后的任何事情,我倾向于将其视为编译器错误,但是...编译器必须支持现有代码,理想情况下,以后的编译器将可以选择使用以前的名称查找规则。(我说的很理想,因为有两组不兼容的名称查找规则显然不是微不足道的。对于大多数编译器实现者来说,仅仅让一组正确就足够困难了。)

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

于 2012-08-29T09:27:28.023 回答
2

maxin的调用Imax依赖于 T,因此 max 应该在模板定义上下文(模板 max 所在的位置)中进行搜索,并与实例化上下文中的参数相关查找相结合。intADL 不应该找到没有关联命名空间的独立最大值。所以我认为 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 查找在实例化点找到了非模板最大值。

于 2012-08-29T09:26:52.857 回答