模板func和非模板func调用顺序

Template func and non template func call order

本文关键字:func 调用 顺序 模板      更新时间:2023-10-16

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

在预标准C++中,您可能会得到非模板max。(如果没有标准,很难说你应该得到什么,但所有我认识的标准前编译器会将名称查找推迟到实例化。)由于C++89,您应该得到模板max;名字查找发生在两个阶段:定义模板时(此时,仅模板max是可见的)并且当模板被实例化时,但在实例化时,仅适用于从属名称,并且仅使用ADL。在代码中,max是一个从属名称,但符号触发ADL的是std::vector(引入std)和int不添加任何内容,甚至不添加全局命名空间。所以未找到非模板CCD_ 8。

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

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

Imaxmax的调用取决于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查找找到非模板最大值。