14

Xcode 4.1 および Visual Studio 2008 で、c++ 標準 ISO/IEC 14882-03 14.6.1/9 のコードをテストします。2 つのコンパイラの出力は、両方とも標準の期待される結果とは異なります。

コードは以下に貼り付けます。

#include <stdio.h>
#include <iostream>
using namespace std;

void f(char);

template <class T > void g(T t)
{
    f(1);
    f(T(1));
    f(t);
}

void f(int);
void h()
{
    g(2);
    g('a');
}

void f(int)
{
     cout << "f int" << endl;
}


void f(char)
{
    cout << "f char" << endl;
}


int main() { 
    h();  
    return 0;
}

規格の説明として。期待される出力は

f char
f int
f int
f char
f char
f char

Xcode 4.1 でコードをビルドして実行します。出力は以下のとおりです。ビルド設定で、「Compiler for C/C++/Object-C」を Apple LLVM Compiler 2.1、Gcc 4.2、LLVM GCC 4.2 に変更しようとしました。出力は同じです。

f char
f char
f char
f char
f char
f char

Microsoft Visual Studio 2008 でコードをビルドして実行します。出力は次のとおりです。

f int
f int
f int
f int
f char
f char

規格の説明(14.6.1/9)を以下に貼り付けます。

名前が (14.6.2 で定義されているように) テンプレートパラメータに依存しない場合、その名前の宣言 (または宣言のセット) は、名前がテンプレート定義に現れるポイントでスコープ内にあるものとします。名前はその時点で見つかった宣言 (または複数の宣言) にバインドされ、このバインディングはインスタンス化の時点で可視である宣言の影響を受けません。[例:

void f(char);
template<class T> void g(T t)
{
f(1); // f(char) 
f(T(1)); // dependent 
f(t); // dependent 
dd++; // not dependent
}
void f(int);
double dd;
void h()
{
// error: declaration for dd not found
g(2); // will cause one call of f(char) followed // by two calls of f(int)
g(’a’); // will cause three calls of f(char) 

—終わりの例]

コードはコンパイラにとって整形式ですが、出力は異なります。このコードを別のプラットフォームに移植することは非常に危険です。

これらのコンパイラが標準に従わない理由を知っている人はいますか?

2011 年 10 月 11 日に編集

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#197によると、標準の例は間違っています以下のコードを Clang と Gcc でテストします。

#include <stdio.h>
#include <iostream>
using namespace std;

void f(char);

template <class T > void g(T t)
{
    f(1);
    f(T(1));
    f(t);
}

enum E{ e };

void f(E );
void h()
{
    g(e);
    g('a');
}

void f(E )
{
    cout << "f E" << endl;
}

void f(char)
{
    cout << "f char" << endl;
}

int main() { 
    h();  
    return 0;
}

期待どおりの出力。

f char
f E
f E
f char
f char
f char

ありがとう、

ジェフリー

4

3 に答える 3

5

あなたが遭遇しているのは、VisualStudioが2フェーズルックアップを実装していないという事実です。テンプレートをインスタンス化するときにのみ、実際の名前を検索します。

そして、Microsoftはこの時点で、2フェーズルックアップのサポートには関心がないとほぼ判断しています。

于 2011-10-03T04:08:37.520 に答える
3

最初の例で述べたように、これは 2 フェーズの名前検索のインスタンスであり、GCC と Clang の両方が実装していますが、MSVC は実装していません。この場合、GCC と Clang の両方が正しいです。実際には、C++コアの欠陥レポート #197に記載されているように、間違っているのは標準です。C++11 標準には別の例が含まれています。

これは、MSVC (2 フェーズの名前ルックアップを実装していない) または GCC (最近まで 2 フェーズの名前ルックアップを一様に実装していなかった) から Clang にコードを移植するときによく見られる問題の 1 つです。

于 2011-10-11T00:14:09.360 に答える
2

これが不適切な動作であることに同意することを除いて、何を伝えればよいかわかりません。

おそらく起こっていることは、MSVC の場合、テンプレート以外の呼び出しの場合に使用すべきではない、後で定義された関数の知識で終わるという犠牲を払って、コンパイラが余分なパスを最適化していることだと思います。正直に言うと、GCC/LLVM がどのような結果になるかはわかりません。結果は、ルールではなく例外として期待されるものだからです。

http://bugreport.apple.com/http://connect.microsoft.com/にバグとして報告して、彼らの言うことを見てみたいと思いますか?

于 2011-10-03T03:47:50.437 に答える