2

次のコードはGCC4.7およびclang3.0でコンパイルされますが、MSVC10ではコンパイルされません。

template <typename X>
struct point
{
    template <typename Seq>
    struct point_iterator
    {
        template <typename T> 
        struct deref;

        template <typename Sq>
        struct deref<point_iterator<Sq> >
        {
        };
    };
};

int main()
{
    typedef point<int> point_t;
    typedef point_t::point_iterator<point_t> Iterator;
    Iterator::deref<Iterator> m;
}

MSVCが提供するコンパイラエラーは次のとおりです。

test.cpp
testcpp(21) : error C2079: 'm' uses undefined struct 'point<X>::point_iterator<Seq>::deref<T>'
        with
        [
            X=int,
            Seq=point_t
        ]
        and
        [
            T=Iterator
        ]

問題の型は、の部分的な特殊化と一致する必要があるため、定義する必要があると思いますderef

  1. これは有効なコードですか?もしそうなら、それを拒否することはMSVC側のバグですが、バグがすでに報告されているかどうか誰かが知っていますか?
  2. それがバグである場合、誰かがそれの回避策を知っていますか?
4

2 に答える 2

0

元のコード

以下はVisualC++ Express 2010でコンパイルされますが、間違った答えが生成されます。

#include <iostream>

template <typename X>
struct point
{
    template <typename Seq>
    struct point_iterator
    {
        template <typename> 
        struct deref 
        {
                static const int value = 0;
        };

        template <typename Sq>
        struct deref< point_iterator<Sq> > 
        { 
                static const int value = 1; 
        };
    };
};

int main()
{
    typedef point<int> point_t;
    typedef point_t::point_iterator<point_t> Iterator;
    int v = Iterator::deref<Iterator>::value;
    std::cout << v << "\n"; // prints 1 on gcc 4.5.1, prints 0 on VC++ 2010
    return 0;
}

これはあなたが得たコンパイルエラーを説明しています:VC++はderefあなたが定義しなかったプライマリテンプレートをインスタンス化しようとしました。この時点で、VC ++にエラーがあり、gcc/clangが優れたコンパイラであるように見える場合があります。

中間の「解決策」

ただし、point_iteratorとそのネストさderefれた名前空間を外部の名前空間に移動すると、 detailgccとVC++の両方で同じですが間違った結果になります。呼び出すdetail::point_iterator::derefと必要なものが得られますが、ネストされたpoint_iterator内部を呼び出すとpoint、gccとVC++の両方で間違った結果が得られるようになりました。したがって、ネストされたテンプレートは、一般的にコンパイラでは難しいようです。

#include <iostream>

namespace detail {
    template <typename Seq>
    struct point_iterator
    {
        template <typename> 
        struct deref 
        {
                static const int value = 0;
        };

        template <typename Sq>
        struct deref< point_iterator<Sq> > 
        { 
                static const int value = 1; 
        };
    };
}

template<typename X>
struct point
{
        template<typename Seq>
        struct point_iterator
        :
                public detail::point_iterator<Seq>
        {};
};

int main()
{
    typedef point<int> point_t;

    typedef point_t::point_iterator<point_t> Iterator1;
    int v1 = Iterator1::deref<Iterator1>::value;
    std::cout << v1 << "\n"; // prints 0 on both gcc 4.5.1 and VC++ 2010

    typedef detail::point_iterator<point_t> Iterator2;
    int v2 = Iterator2::deref<Iterator2>::value;
    std::cout << v2 << "\n"; // prints 1 on both gcc 4.5.1 and VC++ 2010

    return 0;
}

推奨されるアプローチ

ネストされたテンプレートには他にも問題があります。外部テンプレートも特殊化せずに内部テンプレートを明示的に特殊化することはできません(皮肉なことに、VC ++ではこの非標準機能を使用できます!)。これは、ダミーのテンプレートパラメータを使用し、それらを部分的に特殊化することで解決できます(ただし、このダミーのテンプレートパラメータにデフォルト値を指定すると、VC ++では偽のコンパイラ警告を抑制する必要があります)。

したがって、取得したネストされたテンプレート階層全体を解きほぐし、3つの個別のテンプレートを定義して、好みに合わせて特殊化することをお勧めします。これにより、最も簡単なコードが生成され、驚くことはありません。

#include <iostream>

template<typename X>
struct point {};

template <typename Seq>
struct point_iterator {};

template <typename> 
struct deref 
{
        static const int value = 0;
};

template <typename Sq>
struct deref< point_iterator<Sq> > 
{ 
        static const int value = 1; 
};

int main()
{
    typedef point<int> point_t;
    typedef point_iterator<point_t> Iterator1;
    int v = deref<Iterator1>::value;
    std::cout << v << "\n"; // prints 1 on both gcc 4.5.1 and VC++ 2010

    return 0;
}
于 2012-08-13T09:28:49.547 に答える
0

問題は、クラスを特殊化したことに MSVC10 が同意しないことです。これを試してみると

    template <typename Sq>
    struct deref
    {
       typedef int basic;
    };

    template <typename Sq>
    struct deref<point_iterator<Sq> >
    {
       typedef int special;
    };

gcc には存在しますIterator::deref<Iterator>::specialが、MS にはbasic存在するだけです。

あなたのコードは正しいと思います。

部分的な特殊化のみが影響を受けるようです。int期待通りの作品に特化。

于 2012-08-11T22:58:49.837 に答える