Skip to content

Range for loop for statements#545

Open
Alvov1 wants to merge 8 commits into
SRombauts:masterfrom
Alvov1:181-feature-statement-iterator
Open

Range for loop for statements#545
Alvov1 wants to merge 8 commits into
SRombauts:masterfrom
Alvov1:181-feature-statement-iterator

Conversation

@Alvov1

@Alvov1 Alvov1 commented Jun 1, 2026

Copy link
Copy Markdown

Closes #181

Adds a nested RowIterator class to Statement that enables range-based for loops over query results:

SQLite::Statement query(db, "SELECT id, name FROM test");
for (SQLite::Statement& row : query)
{
    std::cout << row.getColumn(0).getInt() << "\n";
}

Notes:

  • begin() calls reset() automatically, so re-iterating the same Statement always starts from the beginning
  • Bindings set before the loop are preserved across reset()
  • Empty result sets are handled correctly (loop body never executes)
  • RowIterator satisfies std::input_iterator_tag with full iterator traits

@Alvov1 Alvov1 force-pushed the 181-feature-statement-iterator branch from fbb99e8 to 83bb827 Compare June 2, 2026 06:32
@SRombauts SRombauts self-assigned this Jun 2, 2026
SQLITECPP_API RowIterator& operator++();

/// Return true when two iterators do not point to the same row.
SQLITECPP_API bool operator!=(const RowIterator& aOther) const;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description calls this "full iterator traits." The traits are all here, but the interface isn't: there's no operator== and no post-increment operator++(int) next to this operator!=. Range-based for only calls operator!=, so nothing breaks today. The catch is that anyone who reaches for it with <algorithm>, or checks it against the C++20 std::input_iterator concept (which requires ==), hits a wall. Either add operator== and post-increment, or soften the claim to "usable in range-based for loops."

Comment thread include/SQLiteCpp/Statement.h Outdated

/// Construct an end sentinel (no associated Statement).
RowIterator() = default;
RowIterator(const RowIterator&) = default;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is redundant: the copy constructor gets generated anyway. Declaring it also has two quiet side effects: it makes implicit copy-assignment deprecated, and it suppresses the implicit move members, so moves fall back to copy (harmless for a single pointer, but not the intent). The RowIterator() = default; above it is the one that's actually needed, since the Statement* constructor suppresses the implicit default constructor. For a trivial pointer holder I'd drop this line and let copy, move, assignment, and the destructor stay implicit (Rule of Zero). Not blocking.

Comment thread src/Statement.cpp
}


// Return a UTF-8 string containing the SQL text of prepared statement with bound parameters expanded.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor and not blocking, not really an issue: the diff drops a blank line here (and another around prepareStatement() below) that aren't part of the iterator change. You could revert them to keep the diff focused, but it's completely fine to leave as-is if you prefer.

@Alvov1 Alvov1 force-pushed the 181-feature-statement-iterator branch from 300d023 to c996909 Compare June 12, 2026 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement iterators and range-based for loops

2 participants