2016-02-28 3 views
3

Рассмотрим следующий класс:итераторов удовлетворение

template <class T> 
struct X { 
    T& operator*() & { return t; } 
    T& operator*() && = delete; 
    X& operator++() { return *this; } 
    T t; 
}; 

Удовлетворяет ли этот класс требованиям концепции итератор стандарта C++? Объект данного класса является инкрементным и разыменованным. Но разыменование объекта rvalue запрещено.

int main() { 
    X<int> x; 
    *x; // ok 
    *X<int>(); // fail. But is it really necessary for Iterator by Standard? 
} 
+1

Действительно ли это C++? – 6502

+0

@ 6502 добавлен как tag 'C++ 14' – alexolut

+0

Я не знаю, что означает' && = delete', должно быть указано – 6502

ответ

2

При строгом чтении стандарта; [iterator.iterators]/2 (§24.2.2/2) делает намек на тип X квалификационный как итератор;

... a и b обозначают значения типа X или const X

... r обозначает значение X& ...

A Тип X удовлетворяет требованиям итератора, если:

  • X удовлетворяет требованиям CopyConstructible, CopyAssignable, a nd Destructible требования ([utility.arg.requirements]) и lvalues ​​типа X являются заменяемыми ([swappable.requirements]), и
  • выражения в таблице (ниже) действительны и имеют указанную семантику.

    • *r (r является разыменовываемым)
    • ++r (возвращает X&)

Учитывая код;

template <class T> 
struct X { 
    T& operator*() & { return t; } 
    T& operator*() && = delete; 
    X& operator++() { return *this; } 
    T t; 
}; 
int main() 
{ 
    X<int> x; 
    ++x; 
    int i = *x; 
    X<int> y(x); 
    using std::swap; 
    std::swap(x, y); 
} 

Конечно, похоже, удовлетворяет этим требованиям.

Тем не менее, история продолжается, итератора Концепция, как определено выше, не указан в качестве одного из итератора категорий в стандартном §24.2.1/2;

Настоящий стандарт определяет пять категорий итераторов, в соответствии с операциями, определенными на них: итераторы ввода, вывода итераторы, форвардные итераторов, двунаправленные итераторы и случайные итераторы доступа ...

Все они определяют операция *a and *r++, для которой тип X не скомпилирован;

int j = *x++; // fails to compile even with the inclusion of the post increment operator 
const X<int> xc {}; 
int ic = *x1; // no const overloads 

Для итератора, который будет использоваться в пределах одной из определенных категорий, она должна включать в себя дополнительные элементы для де ссылок const ценности, lvalues ​​и rvalues, почтовое приращение и т.д. В spirit of the standard;

Итераторы - это обобщение указателей, которые позволяют программе на С ++ работать с различными структурами данных (контейнерами) единообразно.

Руководство здесь для перегруженных членов и операторов является то, что они могут/должны быть добавлены для обеспечения соблюдения и оптимизации (если это возможно) реализацию семантики обобщенной указателю - не запретить семантику; ограничение семантики может иметь непреднамеренные последствия.

+0

Возможно, я не очень хорошо сформулировал исходный вопрос. Главное, что я хотел знать, важно ли реализовать концепцию Iterator (пусть это будет 'ForwardIterator') для предоставления оператора разыменования для rvalue. Если это важно, я хотел бы увидеть пример, который не будет компилироваться из-за того, что оператор разыменования, объявленный как '= deleted'. В то же время, согласно классу Standard, удовлетворяют требованиям этого типа итератора (например, 'ForwardIterator'). – alexolut

+0

* для обеспечения оператора разыменования для rvalue * - да важно (учитывая перечисленные категории) предоставить оператор, подходящий для rvalue, в общем случае это обычный оператор, применяемый к l значениям и r значениям; то есть операторы вообще не ref-qual (один для const и один для не const). * Если это важно, я хотел бы увидеть пример * - как указано выше 'int j = * x ++;' не удалось скомпилировать. Другой простой ответ был бы для идиоматического 'int i = * cont.begin();' Итератор, возвращаемый 'begin()', используется здесь как rvalue. – Niall

+0

Вы уверены в 'int j = * x ++'? [Live test работает отлично] (http://melpon.org/wandbox/permlink/oLI9MIyFdt4d2545). – alexolut

1

Ну, стандарт ничего не знаю о rvalue ссылочных итераторах не говорит. И даже не распознал итераторы, чьи члены перегружены их ссылочными типами. Но ваш код кажется приемлемым будет iterator *, потому что в определении требований к итератору ...

Цитируя раздел 24.2.2 последнего C++14 standard draft, (курсив мой)

24.2.2.2: тип X удовлетворяет требованиям Iterator, если:

- X удовлетворяет CopyConstructible, CopyAssignable и разрушаемых требования (17.6.3.1) и lvalues ​​ типа X является заменой (17.6.3.2), и

- выражения в таблице 106 являются действительными и имеют указанную семантику.

  • * г: г разыменовываемое

  • ++ г: г incrementable

Кроме этого, нет никаких дополнительных ограничений на итератора.


* Из причины, предполагая, что полученному в результате X<typename ...> удовлетворяет первое условие перечисленного

+1

указывает на необходимость замены переменных lvalues ​​и может не применяться к другим предложениям. Если мы применим к нему _ существование существования поддержки существования общего правила, то все остальные требования должны применяться и к значениям r. –

+0

Я тоже так думал, но, я думаю, OP добавляет дополнительное ограничение для своего «итератора», которое, я думаю, должно быть допустимым для его использования, в конце концов, мы иногда перегружаем функции на основе ссылочных типов. Но в строгом смысле его вопросов стандарт не распознает итераторы, чьи члены перегружены ссылкой. Я изменил свой ответ. – WhiZTiM

+3

@Revolver_Ocelot ["r обозначает значение' X & '"] (http://eel.is/c++draft/iterator.требования № iterator.requirements.general-12), поэтому это значение lvalue. Однако просто удовлетворение Итератора бесполезно; вам нужно хотя бы InputIterator или OutputIterator. И оба они требуют работы '* r ++'. –

Смежные вопросы