6

Sun Studio 12.1に移行し、新しいコンパイラ[CC:Sun C ++ 5.10SunOS_sparc2009/06/03]を使用します。以前のバージョンのSunCompiler[CC:Sun WorkShop 6 update 2 C ++ 5.3 2001/05/15]で正常にコンパイルされたコードをコンパイルしているときに、コンパイルエラーが発生します。

これは私が得るコンパイルエラーです。

"Sample.cc":エラー:main()に必要なLoopThrough(int [2])に一致するものが見つかりませんでした。1エラーが検出されました。***エラーコード1。

コード:

#include <iostream> 

#define PRINT_TRACE(STR) \
std::cout << __FILE__ << ":" << __LINE__ << ":" << STR << "\n";

template<size_t SZ>
void LoopThrough(const int(&Item)[SZ])
{
    PRINT_TRACE("Specialized version");
    for (size_t index = 0; index < SZ; ++index)
    {
        std::cout << Item[index] << "\n";
    }
}


/*     
    template<typename Type, size_t SZ>
    void LoopThrough(const Type(&Item)[SZ])
    {
        PRINT_TRACE("Generic version");        
    }
 */  



int main()
{
    {
       int arr[] = { 1, 2 };
       LoopThrough(arr);    
    }
}

Genericバージョンでコードのコメントを外すと、コードは正常にコンパイルされ、Genericバージョンが呼び出されます。拡張機能が無効になっているMSVC2010でこの問題が発生することはなく、ideoneでも同じ問題が発生します。関数の特殊バージョンが呼び出されます。問題は、これはSunCompilerのバグですか?

はいの場合、どのようにしてバグレポートを提出できますか?

4

2 に答える 2

2

この場合、コンパイラは標準に準拠しておらず、バグがあります。関連するセクションを確認しましょう。

最初に13.3/3から:

..。

—最初に、候補関数のサブセット(適切な数の引数を持ち、他の特定の条件を満たす関数)を選択して、実行可能な関数のセットを形成します(13.3.2)。

—次に、各引数を各実行可能関数の対応するパラメーターに一致させるために必要な暗黙の変換シーケンス(13.3.3.1)に基づいて、実行可能な最良の関数が選択されます。

したがって、両方の関数は同じ数の引数を持ち、候補と見なされます。ここで、実行可能な最良の関数を見つける必要があります。

13.3.3:

ICSi(F)が、リスト内のi番目の引数を実行可能な関数Fのi番目のパラメーターのタイプに変換する暗黙の変換シーケンスを示すとします。13.3.3.1は暗黙の変換シーケンスを定義し、13.3.3.2は1つの暗黙の変換の意味を定義します。シーケンスが別のシーケンスよりも良い変換シーケンスまたは悪い変換シーケンスになる

次に、

これらの定義を前提として、すべての引数iについて、ICSi(F1)がICSi(F2)よりも悪い変換シーケンスではない場合、実行可能な関数F1は別の実行可能な関数F2よりも優れた関数であると定義されます。

—一部の引数jの場合、ICSj(F1)はICSj(F2)よりも優れた変換シーケンスです。そうでない場合は、

— F1は非テンプレート関数であり、F2はテンプレート関数の特殊化です。そうでない場合は、

— F1とF2はテンプレート関数であり、F1の関数テンプレートは、14.5.5.2で説明されている半順序規則に従って、F2のテンプレートよりも特殊化されています。そうでない場合は、

2つの関数は最初のルール(constを追加)では等しく、2番目のルールは適用されません(両方ともテンプレートです)。そこで、3番目のルールに移ります。14.5.5.2(要求された場合は引用します)からconst int、関数のバージョンはバージョンよりも特殊化されていることがわかります。const Itemしたがって、最適な一致はconst intオーバーロードであり、これを呼び出す必要があります。

一時的な最善の修正は、おそらく2番目の過負荷です。

template<size_t SZ>
void LoopThrough(int (&Item)[SZ])
{
    LoopThrough(static_cast<const int (&)[SZ]>(Item));
}
于 2012-09-26T21:06:42.767 に答える
1

コンパイラにバグがあります。両方のオーバーロードにはテンプレート引数が推定されており、オーバーロードの解決では最も特殊なものを選択する必要があります。では、新しいコンパイラを入手する以外に、何ができるでしょうか。

まず、コンパイラに準拠している場合でも、さまざまな関数テンプレートのオーバーロードを設定することは一般的に適切ではないことを理解しておくと役立ちます。たとえば、C ++コーディング標準の項目66:ハーブサッターとアンドレイアレキサンドレスクによる101のルール、ガイドライン、およびベストプラクティスを参照してください。

幸いなことに、そのアイテムは可能な修正も提案しています。必要なのは、単一の関数テンプレートを定義し、その関数テンプレートに作業をクラステンプレート関数オブジェクトに委任させることだけです。次に、このクラステンプレートをに部分的に特化できますints

#include <iostream> 

#define PRINT_TRACE(STR) \
std::cout << __FILE__ << ":" << __LINE__ << ":" << STR << "\n";

namespace detail {    

// primary template
template<typename Type, size_t SZ>
class LoopThroughHelper
{
public:
    void operator()(const Type(&Item)[SZ]) 
    {
        PRINT_TRACE("Generic version");        
    }
}; 

// partial specialization for int arrays
template<size_t SZ>
class LoopThroughHelper<int, SZ>
{
public:
    void operator()(const int(&Item)[SZ]) 
    {
        PRINT_TRACE("Specialized version");
        for (size_t index = 0; index < SZ; ++index)
        {
            std::cout << Item[index] << "\n";
        }
    }
}; 

} // namespace detail

// one function template to rule them all
template<typename Type, size_t SZ>
void LoopThrough(const Type(&Item)[SZ])
{
     detail::LoopThroughHelper<Type, SZ>()(Item);        
}

int main()
{
    {
       int arr[] = { 1, 2 };
       LoopThrough(arr);    
    }
}

ほとんどの場合、コンパイラは関数オブジェクトへの呼び出しをインライン化し、一時的なものを完全に最適化します。うまくいけば、コンパイラはクラステンプレートの部分的な特殊化も正しく実装しているでしょう。

Ideoneの出力

于 2012-07-21T16:48:43.860 に答える