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++では、非テンプレートを取得する可能性がありますmax(標準がないと、何を取得するかを言うのは難しいですが、私が知っているすべての先行標準コンパイラは、名前検索をインスタンス化に延期します。)C ++ 89以降、テンプレートを取得する必要がありますmax。名前のルックアップは2つのフェーズで行われます。テンプレートが定義されたとき(この時点ではテンプレートのみmaxが表示されます)と、テンプレートがインスタンス化されたときですが、インスタンス化ポイントでは、依存する名前に対してのみ、ADLのみが使用されます。あなたのコードでmaxは、は依存する名前ですが、ADLをトリガーするシンボルはstd::vector(描画するstd)とintであり、グローバル名前空間でさえも何も追加しません。したがって、非テンプレートmaxは見つかりません。

これらのルールはC++委員会によって最後に公式化されたものであり、コンパイラーは一夜にして変更することはできません。したがって、実際には、コンパイラーの日付が1995年より前の場合は、標準以前の動作が期待できます。後で、私はそれをコンパイラエラーと見なす傾向がありますが...コンパイラは既存のコードをサポートする必要があり、理想的には、後のコンパイラには以前の名前検索ルールを使用するオプションがあります。(理想的には、互換性のない名前検索ルールのセットが2つあることは明らかに重要であるためです。ほとんどのコンパイラー実装者にとって、1つのセットを正しく取得することは十分に困難です。)

そして、Microsoftのテンプレートの実装が今日でも標準に準拠していないことはかなりよく知られています。

于 2012-08-29T09:27:28.023 に答える
2

inの呼び出しはTmaxImax依存するため、maxはテンプレート定義コンテキスト(テンプレートmaxがあります)で検索し、インスタンス化コンテキストで引数依存のルックアップと組み合わせる必要があります。int名前空間が関連付けられていないため、ADLは独立した最大値を見つけるべきではありません。だから私の考えは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が検出されます。

于 2012-08-29T09:26:52.857 に答える