2

以下代码可使用 GCC 4.7 和 clang 3.0 编译,但不能使用 MSVC 10:

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

问题是 MSVC10 不同意你专门化了这个类。如果你试试这个

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

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

你会发现它Iterator::deref<Iterator>::special存在于 gcc 中,但只有 MSbasic存在。

我确实认为您的代码是正确的。

似乎只有部分专业化受到影响。专门从事int预期的工作。

于 2012-08-11T22:58:49.837 回答
0

您的原始代码

以下在 Visual C++ 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到外部命名空间detail会为 gcc 和 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 回答