Advent of Code 2017, Day 1: Sum of digits matching the next digit (circular list) I haven't used C++ for quite a while and wanted to practice a bit, so I decided to start simple and work through the Advent of Code 2017.

This is my solution to Part 1 of the Day 1 exercise "Inverse Captcha":


  The captcha requires you to review a sequence of digits (your puzzle
  input) and find the sum of all digits that match the next digit in the
  list. The list is circular, so the digit after the last digit is the
  first digit in the list.
  
  For example:
  
  
  1122 produces a sum of 3 (1 + 2) because the first digit (1) matches the second digit and the third digit (2) matches the fourth
  digit.
  1111 produces 4 because each digit (all 1) matches the next.
  1234 produces 0 because no digit matches the next.
  91212129 produces 9 because the only digit that matches the next one is the last digit, 9.
  


My program works as follows:


Read one line from stdin
Convert the line character-wise to a vector of decimal digits
Calculate the sum of matching digits
Write the result to stdout




#include &lt;algorithm&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;

// Convert the first line of the input stream to a vector of digits.
std::vector&lt;int&gt; read_digits(std::istream&amp; input) {
    std::string line;
    std::getline(input, line);

    std::vector&lt;int&gt; digits(line.size());
    std::transform(
        std::cbegin(line), std::cend(line), std::begin(digits),
        [](char c) { return c - '0'; }
    );
    return digits;
}

// Return the sum of all digits in the list that match the next digit
// (the first digit is the "next" digit of the last digit).
int reverse_captcha(const std::vector&lt;int&gt;&amp; digits) {
    int sum = 0;
    for (auto p = std::begin(digits); p != std::end(digits); p++) {
        auto next_p =
            (std::next(p) == std::end(digits)) ?
            std::begin(digits) : std::next(p);
        if (*p == *next_p) sum += *p;
    }
    return sum;
}

int main() {
    std::cout &lt;&lt; reverse_captcha(read_digits(std::cin)) &lt;&lt; '\n';
}


I'm compiling it with clang++-4.0 -std=c++14. I'm not sure if I actually use features of the newest standard, but I don't want to restrict myself to older versions.

Here are a few things I'm particularly curious about:


How can I separate iterating over the pairs of digits from calculating their sum if the pairs are equal? If I were using Python I would write one or two small generator functions, but I don't know yet if there is an equally simple way to do this in C++, or if this would become overkill.
Is there an elegant way to avoid the extra step of constructing a string line before creating the vector of digits?
Using - '0' for converting char &rarr; int feels like a hack to me, is there really no purpose-built function for this? (I'm used to int('5') &rarr; 5 from Python)
I think std::rotate can lead to a somewhat simpler approach:


get the input
create a copy
rotate the copy by one element
Accumulate the sum of elements that match between the two


Code might look something on this general order:

int sum_matching(std::vector&lt;int&gt; const &amp;digits) {
    std::vector&lt;int&gt; copy{digits};

    std::rotate(copy.begin(), copy.begin()+1, copy.end());

    int sum = 0;
    for (int i=0; i&lt;digits.size(); i++)
        if (digits[i] == copy[i])
            sum += digits[i];
    return sum;
}


I'm pretty sure you could hijack std::inner_product to do that final loop, but given its name, that would be misleading, so probably better avoided. On the other hand, if your compiler includes all the latest C++17 goodness, you could use std::transform_reduce though:

int main() {
    std::vector&lt;int&gt; inputs{1, 2, 3, 3, 1};

    std::vector&lt;int&gt; copy{inputs};
    std::rotate(copy.begin(), copy.begin()+1, copy.end());

    int result = std::transform_reduce(inputs.begin(), inputs.end(), 
                    copy.begin(), 
                    0,
                    [](int a, int b) { return a + b; },
                    [](int a, int b) { return a==b ? a : 0; });

    std::cout &lt;&lt; result &lt;&lt; "\n";
}


If you'd like to play with that using a (strictly prototype) implementation of transform_reduce, it's not terribly complex--something on this order:

template&lt;class InputIterator1, 
         class InputIterator2, 
         class T, 
         class BinaryOperation1, 
         class BinaryOperation2&gt;
T transform_reduce(InputIterator1 first1, InputIterator1 last1,
                    InputIterator2 first2,
                    T init,
                    BinaryOperation1 binary_op1,
                    BinaryOperation2 binary_op2) 
{
    for ( ; first1 != last1; ++first1, ++first2) {
        init = binary_op1(init, binary_op2(*first1, *first2));
    }
    return init;
}


Note, however, that this is a purely serial implementation--part of the intent of transform_reduce is that it will support parallel implementation, which this doesn't (but that's mostly a restriction that binary_op1 and binary_op2 must be commutative and associative, not a requirement on the implementation). Note that the standard includes a number of overloads of std::transform_reduce--I've included an implementation of the one used in the preceding code.