【问题标题】:MSVC compiler bug causing error with iterators and friend functions?MSVC 编译器错误导致迭代器和友元函数出错?
【发布时间】:2016-05-18 20:46:58
【问题描述】:

我一直在做一个小规模的测试,看看我是否可以用一个更大的容器找出一些特定于编译器的大规模问题。以下代码在 GCC 中运行良好,但在 Visual Studio 2010 和 2013 中会导致以下错误代码:

“错误 1 ​​错误 C2675: 一元 '--' : 'std::iterator' 未定义此运算符或转换为预定义运算符可接受的类型 d:\programming\workspaces\adl_test\main.cpp 127 1 adL_test_msvc"

测试代码如下:

#include <iostream>
#include <iterator>

namespace nsp
{

template <class element_type, class element_allocator_type = std::allocator<element_type> >
class test_container
{
private:
    element_type numbers[50];
    friend class iterator;
    friend class reverse_iterator;

public:
    class reverse_iterator; //forward decl

    class iterator : public std::iterator<std::bidirectional_iterator_tag, element_type>
    {
    private: 
        element_type *i;

        template <class distance_type>
        friend void advance(reverse_iterator &rit, distance_type n);
    public: 

        iterator() {}

        iterator(element_type &_i)
        {
            i = &(_i);
        }

        element_type & operator *()
        {
            return *i;
        }

        iterator & operator = (const element_type &source_i)
        {
            i = &(source_i);
            return *this;
        }

        iterator & operator = (const iterator &source)
        {
            i = source.i;
            return *this;
        }

        bool operator != (const iterator rh)
        {
            return i != rh.i;
        }

        iterator & operator ++()
        {
            ++i;
            return *this;
        }

        iterator & operator --()
        {
            --i;
            return *this;
        }



        template <class distance_type>
        friend void advance(iterator &it, distance_type n)
        {
            it.i += n;
        }

        friend typename std::iterator_traits<iterator>::difference_type distance(const iterator &first, const iterator &last)
        {
            return last.i - first.i;
        }


    };



    class reverse_iterator : public std::iterator<std::bidirectional_iterator_tag, element_type>
    {
    private: 
        iterator it;

    public: 

        reverse_iterator(element_type &_i)
        {
            it.i = _i;
        }

        reverse_iterator(const iterator &source)
        {
            it = source;
        }

        element_type & operator *()
        {
            return *it;
        }

        element_type & operator = (const reverse_iterator &source)
        {
            it = source.it;
            return *this;
        }

        element_type & operator = (const iterator &source)
        {
            it = source;
            return *this;
        }

        bool operator != (const iterator rh)
        {
            return it != rh.it;
        }

        reverse_iterator & operator ++()
        {
            --it;
            return *this;
        }

        reverse_iterator & operator --()
        {
            ++it;
            return *this;
        }



        template <class distance_type>
        friend void advance(reverse_iterator &rit, distance_type n)
        {
            rit.it.i -= n;
        }

        friend typename std::iterator_traits<reverse_iterator>::difference_type distance(const reverse_iterator &first, const reverse_iterator &last)
        {
            return distance(last.it, first.it);
        }


    };


    iterator begin()
    {
        return iterator(numbers[0]);
    }


    iterator end()
    {
        return iterator(numbers[50]);
    }


};


}


int main(int argc, char **argv)
{
    nsp::test_container<int> stuff;

    int counter = 0;

    for (nsp::test_container<int>::iterator it = stuff.begin(); it != stuff.end(); ++it)
    {
        *it = counter++;
    }

    nsp::test_container<int>::iterator it = stuff.begin(), it2 = stuff.begin();

    using namespace std;

    std::cout << *it << std::endl;

    ++it;
    --it;
    ++it;


    std::cout << *it << std::endl;

    advance(it, 2);

    std::cout << *it << std::endl;

    std::advance(it, 2);

    std::cout << *it << std::endl;

    int distance_between = distance(it2, it);

    std::cout << distance_between << std::endl;

    nsp::test_container<int>::reverse_iterator rit = it, rit2 = it2;

    --rit;
    ++rit;
    advance(rit, -2);

    distance_between = distance(rit2, rit);
    std::cout << distance_between << std::endl;

    std::cin.get();

    return 0;
}

显然 -- 操作符在迭代器上工作正常,如代码中所示,但是当从 reverse_iterator 调用时,MSVC 会产生错误,尽管 reverse_iterator 是朋友。为什么? 这个错误的解决方法是什么?

不要建议处理代码的不同方法(即直接修改 i 而不是调用 -- 运算符),这是一个测试用例,不是实际工作代码。它并不代表实际代码的复杂性,我也不会向您解释为什么实际代码会以这种方式工作,因为我没有时间。

【问题讨论】:

  • iterator 里面的reverse_iterator 是指同级类还是基类?
  • @immibis - 谢谢,这就是问题所在。将更正并发布答案。

标签: c++ visual-studio templates iterator friend


【解决方案1】:

感谢immibus,找到了答案: GCC 认为 reverse_iterator 中的“迭代器”指的是 test_container::iterator,而(出于某种原因)MSVC 2010-2013 认为它指的是基类。 解决方案是在 reverse_iterator 中指定迭代器时更加具体 - 使用“typename test_container::iterator”而不是“iterator”。

更正的代码:

#include <iostream>
#include <iterator>

namespace nsp
{

template <class element_type, class element_allocator_type = std::allocator<element_type> >
class test_container
{
private:
    element_type numbers[50];
    friend class iterator;
    friend class reverse_iterator;

public:
    class reverse_iterator; //forward decl

    class iterator : public std::iterator<std::bidirectional_iterator_tag, element_type>
    {
    private: 
        element_type *i;

        template <class distance_type>
        friend void advance(reverse_iterator &rit, distance_type n);
    public: 

        iterator() {}

        iterator(element_type &_i)
        {
            i = &(_i);
        }

        element_type & operator *()
        {
            return *i;
        }

        iterator & operator = (const element_type &source_i)
        {
            i = &(source_i);
            return *this;
        }

        iterator & operator = (const iterator &source)
        {
            i = source.i;
            return *this;
        }

        bool operator != (const iterator rh)
        {
            return i != rh.i;
        }

        iterator & operator ++()
        {
            ++i;
            return *this;
        }

        iterator & operator --()
        {
            --i;
            return *this;
        }



        template <class distance_type>
        friend void advance(iterator &it, distance_type n)
        {
            it.i += n;
        }

        friend typename std::iterator_traits<iterator>::difference_type distance(const iterator &first, const iterator &last)
        {
            return last.i - first.i;
        }


    };



    class reverse_iterator : public std::iterator<std::bidirectional_iterator_tag, element_type>
    {
    private: 
        typename test_container::iterator it;

    public: 

        reverse_iterator(element_type &_i)
        {
            it.i = _i;
        }

        reverse_iterator(const typename test_container::iterator &source)
        {
            it = source;
        }

        element_type & operator *()
        {
            return *it;
        }

        element_type & operator = (const reverse_iterator &source)
        {
            it = source.it;
            return *this;
        }

        element_type & operator = (const typename test_container::iterator &source)
        {
            it = source;
            return *this;
        }

        bool operator != (const typename test_container::iterator rh)
        {
            return it != rh.it;
        }

        reverse_iterator & operator ++()
        {
            --it;
            return *this;
        }

        reverse_iterator & operator --()
        {
            ++it;
            return *this;
        }



        template <class distance_type>
        friend void advance(reverse_iterator &rit, distance_type n)
        {
            rit.it.i -= n;
        }

        friend typename std::iterator_traits<reverse_iterator>::difference_type distance(const reverse_iterator &first, const reverse_iterator &last)
        {
            return distance(last.it, first.it);
        }


    };


    iterator begin()
    {
        return iterator(numbers[0]);
    }


    iterator end()
    {
        return iterator(numbers[50]);
    }


};


}


int main(int argc, char **argv)
{
    nsp::test_container<int> stuff;

    int counter = 0;

    for (nsp::test_container<int>::iterator it = stuff.begin(); it != stuff.end(); ++it)
    {
        *it = counter++;
    }

    nsp::test_container<int>::iterator it = stuff.begin(), it2 = stuff.begin();

    using namespace std;

    std::cout << *it << std::endl;

    ++it;
    --it;
    ++it;

    std::cout << *it << std::endl;

    advance(it, 2);

    std::cout << *it << std::endl;

    std::advance(it, 2);

    std::cout << *it << std::endl;

    int distance_between = distance(it2, it);

    std::cout << distance_between << std::endl;

    nsp::test_container<int>::reverse_iterator rit = it, rit2 = it2;

    --rit;
    ++rit;
    advance(rit, -2);

    distance_between = distance(rit2, rit);
    std::cout << distance_between << std::endl;

    std::cin.get();

    return 0;
}

【讨论】:

    猜你喜欢
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-18
    • 2020-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多