C++ 为什么我会得到;必须是可修改的l值“;以下代码出现编译器错误(C2105)?

C++ 为什么我会得到;必须是可修改的l值“;以下代码出现编译器错误(C2105)?,c++,compiler-errors,iterator,C++,Compiler Errors,Iterator,我被这个问题难住了…编译器输出: d:\data\personal\projects\test\test.cpp(42):错误C2105:“--”需要l值 #include <iostream> #include <algorithm> #include <iterator> class FOO { public: typedef int* iterator; typedef const int* const_iterator; c

我被这个问题难住了…编译器输出:

d:\data\personal\projects\test\test.cpp(42):错误C2105:“--”需要l值

#include <iostream>
#include <algorithm>
#include <iterator>

class FOO
{
public:
    typedef int* iterator;
    typedef const int* const_iterator;

    class explicit_iterator : public std::iterator< std::bidirectional_iterator_tag, int >
    {
    public:
        explicit_iterator(int* ptr = nullptr) : m_ptr(ptr) {}
        bool operator ==(const explicit_iterator& rhs) const { return m_ptr == rhs.m_ptr; }
        bool operator !=(const explicit_iterator& rhs) const { return m_ptr != rhs.m_ptr; }

        reference operator *() const { return *m_ptr; }

        explicit_iterator& operator ++() { ++m_ptr; return *this; }
        explicit_iterator& operator --() { --m_ptr; return *this; }

    private:
        int* m_ptr;
    };

    FOO(int val = 0) { std::fill( begin(), end(), val ); }

    iterator begin() { return m_data; }
    iterator end() { return m_data + 10; }

    explicit_iterator begin2() { return explicit_iterator( begin() ); }
    explicit_iterator end2() { return explicit_iterator( end() ); }

private:
    int m_data[10];
};

int main (int, char *[])
{
    FOO foo;
    // This is the line that fails!  (Not this one, the one right below!!!)
    std::copy( foo.begin(), --foo.end(), std::ostream_iterator<int>( std::cout, "\n" ) ); // C2105

    // All these variants are good
    std::copy( foo.begin2(), --foo.end2(), std::ostream_iterator<int>( std::cout, "\n" ) ); // good
    std::copy( foo.begin(), foo.end() - 1, std::ostream_iterator<int>( std::cout, "\n" ) ); // good
    int* end = foo.end();
    std::copy( foo.begin(), --end, std::ostream_iterator<int>( std::cout, "\n" ) ); // good

    return 0;
}
#包括
#包括
#包括
福班
{
公众:
typedef int*迭代器;
typedef const int*常量迭代器;
类显式迭代器:公共std::iterator
{
公众:
显式迭代器(int*ptr=nullptr):m_ptr(ptr){}
bool操作符==(const explicit_iterator&rhs)const{return m_ptr==rhs.m_ptr;}
布尔运算符!=(常量显式迭代器&rhs)常量{return m_ptr!=rhs.m_ptr;}
引用运算符*()常量{return*m_ptr;}
显式迭代器&运算符+++(){++m_ptr;返回*this;}
显式迭代器和运算符--(){--m_ptr;返回*this;}
私人:
int*m_ptr;
};
FOO(int val=0){std::fill(begin(),end(),val);}
迭代器begin(){return m_data;}
迭代器end(){return m_data+10;}
显式迭代器begin2(){返回显式迭代器(begin());}
显式迭代器end2(){返回显式迭代器(end());}
私人:
int m_数据[10];
};
int main(int,char*[])
{
富富,;
//这是失败的那一行!(不是这一行,是下面的那一行!!!)
std::copy(foo.begin(),--foo.end(),std::ostream\u迭代器(std::cout,“\n”);/C2105
//所有这些变体都很好
std::copy(foo.begin2(),--foo.end2(),std::ostream\u迭代器(std::cout,“\n”);//很好
std::copy(foo.begin(),foo.end()-1,std::ostream\u迭代器(std::cout,“\n”);//很好
int*end=foo.end();
std::copy(foo.begin(),--end,std::ostream\u迭代器(std::cout,“\n”);//很好
返回0;
}

您不能预先声明右值或指针类型。调用
foo.end()

下一个调用的作用是
--foo.end2()
,因为在本例中,preincrement是一个成员函数,在该语言中,对右值调用成员函数是合法的。该语法相当于更明确的语法,这可能使理解更简单:

foo.end2().operator--();

不能预减缩右值或指针类型。调用
foo.end()

下一个调用的作用是
--foo.end2()
,因为在本例中,preincrement是一个成员函数,在该语言中,对右值调用成员函数是合法的。该语法相当于更明确的语法,这可能使理解更简单:

foo.end2().operator--();

这句话是无效的

std::copy(foo.begin(),--foo.end(),std::ostream_迭代器(std::cout,“\n”);//C2105


函数foo.end()返回一个临时对象,您不能对其应用运算符--。

此语句无效

std::copy(foo.begin(),--foo.end(),std::ostream_迭代器(std::cout,“\n”);//C2105


函数foo.end()返回一个临时对象,您不能对其应用运算符--。

预减量的操作数必须是内置类型(如指针)的可修改左值。参见C++11 5.3.2“增量和减量”

FOO::end()
成员函数返回一个内置类型(指针),该类型是右值,而不是可修改的左值,因此不能对其使用预减量运算符

FOO::end2()
返回一个右值,但不是内置类型。因此可以调用重载的预减量运算符


最后,
--end
作用于可修改的左值。

对于内置类型(如指针),预减量的操作数必须是可修改的左值。参见C++11 5.3.2“增量和减量”

FOO::end()
成员函数返回一个内置类型(指针),该类型是右值,而不是可修改的左值,因此不能对其使用预减量运算符

FOO::end2()
返回一个右值,但不是内置类型。因此可以调用重载的预减量运算符


最后,
--end
作用于一个可修改的左值。

您应该使用
std::prev(foo.end())
。不显示行号,只抛出错误消息和代码而不进一步了解,检查您所拥有的内容是相当繁琐的@KerrekSB似乎已经发现了…@ShafikYaghmour是的,现在看到了。但他不应该让这个评论滚动出去。当我在这里发布代码时,我试图至少避免水平滚动条…为了清晰起见进行了编辑(你们真的很挑剔)@MarkB:记住,你是那个想要回答这个问题的人,其他人正在帮助你解决问题。你提供的任何帮助都是为了你的利益,而不是那些挑剔的家伙。在本例中,该行已被标记,但代码的格式将注释移出了可见空间。对代码进行格式化以使其适合屏幕将有助于您和其他人的未来。您应该使用
std::prev(foo.end())
。无需显示行号,只需抛出错误消息和代码而无需进一步了解,检查您所拥有的内容非常繁琐@KerrekSB似乎已经发现了…@ShafikYaghmour是的,现在看到了。但他不应该让这个评论滚动出去。当我在这里发布代码时,我试图至少避免水平滚动条…为了清晰起见进行了编辑(你们真的很挑剔)@MarkB:记住,你是那个想要回答这个问题的人,其他人正在帮助你解决问题。你提供的任何帮助都是为了你的利益,而不是那些挑剔的家伙。在本例中,该行已被标记,但代码的格式将注释移出了可见空间。对代码进行格式化,使其适合屏幕,这将在将来对您和其他人有所帮助