c++ - Why does my custom iterator require a call operator in range based for loops? -


link mcve.

we define matrix iterable both rows , columns. here's implementation of row-wise iterator:

template<class real> class rowiterator { public:     rowiterator() { }     rowiterator(real* begin, size_t rows, size_t cols) : begin(begin), rows(rows), cols(cols) { }      real* operator*() const { return begin; }     real& operator[](size_t col) const { return begin[col]; }      bool operator!=(const rowiterator& it) const { return begin != it.begin; }     rowiterator& operator++() { begin += cols; --rows; return *this; }  private:     real* begin;     size_t rows, cols; }; 

iterating on our matrix implemented using range object define follows:

namespace details {  template<class iterator> struct range {     iterator begin, end;     range() { }     range(iterator begin, iterator end) : begin(begin), end(end) { } };  template<class iterator> iterator begin(const range<iterator>& range) { return range.begin; } template<class iterator> iterator end(const range<iterator>& range) { return range.end; }  }  using details::range; template<class iterator> range<iterator> make_range(iterator begin, iterator end) { return range<iterator>(begin, end); } 

this our usage code:

range<rowiterator<float>> make_row_range(float* mat, size_t rows, size_t cols) {     return make_range(         rowiterator<float>(mat, rows, cols),         rowiterator<float>(mat + rows * cols, 0, cols)); }  int main() {     size_t rows = 4, cols = 6;     float* mat = new float[rows * cols];     for(size_t = 0; < rows * cols; ++i)         mat[i] = (float)i;     auto rowrange = make_row_range(mat, rows, cols);      // loop works expected     std::cout << "begin, end" << std::endl;     for(auto b = begin(rowrange), e = end(rowrange); b != e; ++b) {         // using rowiterator<t>::operator[](size_t)         std::cout << "start of row: " << b[0] << std::endl;     }      // loop produces confusing compiler errors     std::cout << "range based" << std::endl;     for(auto row : rowrange) {                        // line 42         // row of type float*         std::cout << "start of row: " << row[0] << std::endl;     }     return 0; } 

i compiled above mcve , got following compiler errors:

  • visual studio 2013 (all on line 42):

    error c2064: term not evaluate function taking 0 arguments error c3536: '$s2': cannot used before initialized error c3536: '$s3': cannot used before initialized error c2100: illegal indirection error c2440: 'initializing' : cannot convert 'int' 'float *' 
  • gcc 5.1 (on line 42):

    error: no match call '(rowiterator<float>) ()' 
  • clang 3.7.0 (on line 42):

    error: type 'rowiterator<float>' not provide call operator note: when looking 'begin' function range expression of type 'details::range<rowiterator<float> >' 

all compilers searching call operator. why? as understand, above iterator provides minimal interface ranged loops and works when using syntactical equivalence code cppreference.com.

while writing question came solution (rubber debugging?): compiler first checks members range::begin , range::end , tries invoke leading missing call operator. none of tested compilers indicated in error messages[1]. fix rename them:

namespace range {  template<class iterator> struct range {     // "begin" , "end" have ultra-special meaning in context!!!     iterator range_begin, range_end;     range() { }     range(iterator begin, iterator end) : range_begin(begin), range_end(end) { } };  template<class iterator> iterator begin(const range<iterator>& range) { return range.range_begin; } template<class iterator> iterator end(const range<iterator>& range) { return range.range_end; }  } 

the requirements on class range defined (source: cppreference.com, emphasis mine):

begin_expr , end_expr defined follows:

1 if range_expression expression of array type, begin_expr __range , end_expr (__range + __bound), __bound number of elements in array (if array has unknown size or of incomplete type, program ill-formed)

2 if range_expression expression of class type c has member named begin and/or member named end (regardless of type or accessibility of such member), begin_expr __range.begin() , end_expr __range.end();

3 otherwise, begin_expr begin(__range) , end_expr end(__range), found via argument-dependent lookup (non-adl lookup not performed).

[1]: clang came close, though message ambiguous: thought (adl) looking details::begin(range) instead looking straight @ range::begin.


Comments

Popular posts from this blog

wordpress - (T_ENDFOREACH) php error -

Export Excel workseet into txt file using vba - (text and numbers with formulas) -

Using django-mptt to get only the categories that have items -