2012-02-22 8 views
1
#include <iostream> 

template< typename U > 
struct base { 
    template< typename T > 
    base const & operator<<(T x) const { 
     std::cout << sizeof(x) << std::flush; 
     return *this; 
    } 
}; 

template< typename U > 
struct derived : public base<U> { 
    using base<U>::operator<<; 

    derived const & operator<<(float const & x) const { 
     std::cout << "derived" << std::flush; 
     return *this; 
    } 
}; 

int main() { 
    unsigned char c(3); 
    derived<double> d; 
    d << c; 
    d.operator<<(c); 
    return 0; 
} 

上記のコードの正解を得るには、(テンプレートの積み上げとオーバーライド、積分プロモーションなど...)ルールを説明してください。それは有効ですか?ルールが長すぎる場合は、文章の指針を提供してください。最新のコンパイラは、正しい結果については同意しません。 gcc-4.6とicpc-12.1.0は「11」が正解ですが、VS2010はあいまいさでd << c;をコンパイルすることを拒否しますが、d.operator<<(c);を受け入れます。後者は1 iircを出力します。誰が正しいのか、誰が間違っているのか?次のコードのISO C++標準に準拠した結果

+0

ねえ、違いは何ですか? 'd << c'がMSVCでコンパイルされなければ、印刷する' 1'は1つだけです。他のコンパイラは2つの '1'を出力します。または私は何かを逃していますか? –

+0

関係するデータ型がsizeof == 1:8のデータ型を持たないことを認識する必要があります。しかし、11は実際には2つの「1」のようです。 –

+0

何が欲しいですか?コンパイラを試してみますか? –

答えて

3

"11"が正しい出力です。

両方の式で、派生演算子< <とベース演算子< <の両方が候補です。次に、必要な暗黙の変換シーケンスに基づいて候補を比較します。基本演算子< <は、型Tが引数と一致するように推測されたテンプレート関数であるため、どちらの場合もより良い一致となります。

正確なルールはかなり長いです。詳細は13.3 のワーキンググループの論文のthis listにリンクされている現在のC++ドラフト標準であるn3337のオーバーロード解決にあります。

MSVCが1つのステートメントをコンパイルしない理由を尋ねるなら、私は確かではありませんが、相互に優れていない複数の計算されたICSがある場合、関数呼び出しはあいまいです(13.3 3)。 MSVCはd << cの場合の過負荷の少なくとも一つのために間違ったICSを計算しているようだが、診断は、任意の詳細を与えるものではありません:

error C2666: 'derived<U>::operator <<' : 2 overloads have similar conversions 
     with 
     [ 
      U=double 
     ] 
     ConsoleApplication1.cpp(24): could be 'const derived<U> &derived<U>::operator <<(const float &) const' 
     with 
     [ 
      U=double 
     ] 
     ConsoleApplication1.cpp(14): or  'const base<U> &base<U>::operator <<<unsigned char>(T) const' 
     with 
     [ 
      U=double, 
      T=unsigned char 
     ] 
     while trying to match the argument list '(derived<U>, unsigned char)' 
     with 
     [ 
      U=double 
     ] 
+0

私はあなたが正しいと信じています。私は微妙なことがC++にあり、テンプレート関数以外の関数を選択したいだけでなく、より良い変換シーケンスを選択したいと思っています。テンプレートの変換シーケンスはこの場合には優れています。 13.3.3.1は、非テンプレート関数がテンプレート関数よりも優れているとみなされ、非テンプレート関数の変換シーケンスが悪い場合にのみ適用される場合を示しています。しかし、この場合、テンプレート以外の関数の変換シーケンスは悪化します。 –

0

あなたがoperator <<を求めているので、それがコンパイルされません。自動的に呼び出されます。これはoperator +のようなもので、基本タイプ(換言すればint)に変換できる変換演算子を持つようなものです。たとえば、次のように

class Conversion 
{ 
public: 
    operator int() 
    { 
     return 5; 
    } 

    int operator +(int x) 
    { 
     return 10; 
    } 
}; 

そして、それが好きな使用:operator intも可能ですので、

Conversion conv; 
conv + 1.0; 

ここoperator +は暗黙のうちに、呼び出すことはできません。合格すると、intoperator +(int)が呼び出されます。 doubleとオペレータ+を起動するには、我々は行うことができます:私は、コンパイラのルールを知らない

conv.operator+(1.0); 

、厳格な基準定義を。

私はまた、我々は非テンプレートクラスとしてbasederivedクラスを変更した場合、問題はまだ(/ 11 VC10に)残ること、が分かった:

struct base { 
    base const & operator<<(int x) const { 
     std::cout << sizeof(x) << std::flush; 
     return *this; 
    } 
}; 

struct derived : public base{ 
    using base::operator<<; 
    derived const & operator<<(float const & x) const { 
     std::cout << "derived" << std::flush; 
     return *this; 
    } 
}; 

int main() 
{ 
    derived d; 
    d<<10.0; // ERROR 
} 
関連する問題