Bresenham line drawing implementation
That seems good. I really like the callback mechanism to do whatever we want with the marked positions and not one specific action. That makes for a generic tool; good design. I don't have much to say to improve the algorithm itself, but here are my two cents anyway:


Do you have a using std::swap; anywhere? Otherwise, I don't think that the unqualified calls to swap will work as intended.
While auto is a great tool, there are some times when I don't think that it adds to readability. For example, it took me more time that I would have wanted to see that swap_xy was a bool. That's prone to debate anyway, but I don't think that you will ever replace it by another type and an explicit bool would have highlighted the logic. That's still subjective though.
Still pretty subjective, but instead of this:

auto pen = p0;
while (pen.x != p1.x) {
    // ...
    pen.x += step_x;
}


I would have used a for loop since you explicitly have an initialization, a condition and a step. And everyone uses the same variable pen, which isn't used after the loop.

for (auto pen = p0; pen.x != p1.x; pen.x += step_x) {
    // ...
}

Nitpicking again, but I would have factored the multiplication by 2 out of the std::abs in the computation of error:

auto error = 2 * std::abs(d.y*(pen.x - p0.x) - d.x*(pen.y - p0.y));


By the way, this factorization highlights something else: you actually do not need to keep the multiplication by 2 in error; you only need it for the comparison:

auto error = std::abs(d.y*(pen.x - p0.x) - d.x*(pen.y - p0.y));
while (2 * error &gt; dx_abs) {
    pen.y += step_y;
    error -= dx_abs;
    mark(pen);
    skip = true;
}


Not that it makes a big difference, but it still makes the code a little bit terser.