#include <iterator>
#include <iostream>

template <typename In, typename Out>
   Out t9_transform(In f, In l, Out out)
{
    auto magic = [](decltype(*f) i) { return '2' + std::min(7, (i - (i >> 4)) / 3); };
    decltype(0+*f) previous = 0;

    for(;f!=l;++f) {
        if (*f>='a' && *f<='z') {
            auto idx = *f - 'a';

            auto digit = magic(idx);
            if (digit == previous) *out++ = ' ';
            previous = digit;

            static_assert(std::is_signed<decltype(idx)>::value, "difference type is required to be signed here");
            for (; idx>=0 && digit == magic(idx); --idx)
                *out++ = digit;
        } else
            *out++ = '0';
    }

    return out;
}

std::string t9(std::string const& input)
{
    std::string result;
    // result.reserve(2*input.size());
    t9_transform(begin(input), end(input), std::back_inserter(result));
    return result;
}

int main()
{
    const std::string input = "abcdefghijklmnopqrstuvwxyz";
    auto output = t9_transform(begin(input), end(input), std::ostream_iterator<char>(std::cout));

    std::cout << std::endl << t9("hello world!") << std::endl;

    // or, how about translating all of stdin to stdout, in streaming mode?
    *t9_transform(std::istreambuf_iterator<char>(std::cin), std::istreambuf_iterator<char>(), output) = '\n';
}
