Caesar cipher implementation in C++ I've implemented a Caesar cipher in C++ and would like for you to review it. It works as expected, at least with the inputs I've tried.

Feel free to suggest improvements, warn about bad practices or mistakes that I might be doing or give general tips.

// Caesar Cipher implementation

#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;algorithm&gt;
#include &lt;fstream&gt;
#include &lt;vector&gt;
#include &lt;cassert&gt;
#include &lt;iterator&gt;


std::string encodeStr(const std::string&amp; str, int shift, bool decodeFlag = false)
{
    std::string str_enc;
    // not sure if this function is doing to much
    std::transform(str.cbegin(), str.cend(), std::back_inserter(str_enc), [&amp;](char ch) -&gt; char
    {
        if (ch == 'z' || ch == 'Z')
        {
            return ch - 25;
        }
        else if (isspace(ch))
        {
            return ' ';
        }
        else
        {
            if (islower(ch))
                ch ^= 0x20; // XOR 6th bit don't care if it's lower case.
            if (decodeFlag)
            {
                return ((ch - 'A' + 26) - shift) % 26 + 'A';
            }
            else
            {
                return ((ch - 'A') + shift) % 26 + 'A';
            }
        }
    });
    return str_enc;
}

std::vector&lt;std::string&gt; encodeVec(const std::vector&lt;std::string&gt;&amp; strVector, int shift, bool decodeFlag = false)
{
    std::vector&lt;std::string&gt; tempMsg;
    tempMsg.reserve(strVector.size());

    std::transform(strVector.cbegin(), strVector.cend(), std::back_inserter(tempMsg),
        [&amp;](const std::string&amp; s) { return encodeStr(s, shift, decodeFlag); });

    return tempMsg;
}

int main(int argc, char *argv[])
{
    int choice;
    std::cout &lt;&lt; "What do you want to do? 1.Encrypt, 2.Decrypt: ";
    std::cin &gt;&gt; choice;

    if (!(choice == 1 || choice == 2)) {
        return EXIT_FAILURE;
    }

    int key;
    std::cout &lt;&lt; "Enter desired shift: ";
    std::cin &gt;&gt; key;


    std::ifstream inFile("test.txt"); // Might ask for the file instead of hard coding it...
    if (!inFile)
    {
        std::cout &lt;&lt; "There was a problem with the file!";
        return EXIT_FAILURE;
    }

    std::string line;
    std::vector&lt;std::string&gt; lines;

    while (std::getline(inFile, line))
    {
        lines.push_back(line);
    }

    const std::vector&lt;std::string&gt; finalResult = [&amp;]()
    {
        return choice == 1 ? encodeVec(lines, key) : encodeVec(lines, key, true);
    }();

    std::ofstream outFile("test.txt");
    std::copy(finalResult.cbegin(), finalResult.cend(),
        std::ostream_iterator&lt;std::string&gt;(outFile, "\n"));

    return EXIT_SUCCESS;
}
You can accept arguments from the command line.

You don't need to differentiate between decode and encode, you can simply provide negative shift.

You can hide the big lambda into a char -&gt; char function.

You actually don't need the string -&gt; string nor vector -&gt; vector implementations.

encodeStr is a terrible name :)

You can leverage the char -&gt; char implementation and copy istream_iterator&lt;char&gt; to ostream_iterator&lt;char&gt; char by char, and doing it over std::cin and std::cout will give you the ability to change the files as needed (through pipes) or use standard input / output by default.

#include &lt;iostream&gt;
#include &lt;algorithm&gt;
#include &lt;iterator&gt;
#include &lt;sstream&gt;

const unsigned char caesar_range = 'Z' - 'A' + 1;

char caesar_cipher(char c, int shift)
{
    char offset;
    if (c &gt;= 'a' &amp;&amp; c &lt;= 'z') offset = 'a';
    else if (c &gt;= 'A' &amp;&amp; c &lt;= 'Z') offset = 'A';
    else return c;

    shift = shift % caesar_range;
    auto base = c - offset + shift;
    if (base &lt; 0) {
        base = caesar_range + base;
    }
    return base % caesar_range + offset; 
}

void caesar_usage()
{
    std::cout &lt;&lt; "Usage caesar &lt;shift&gt;\n";
    std::cout &lt;&lt; "\tshift must be integer and providing -shift decodes string encoded with shift.\n";
}

int main(int argc, char *argv[])
{
    if (argc != 2) {
        caesar_usage();
        return EXIT_FAILURE;
    }

    int shift;
    std::stringstream ss(argv[1], std::ios_base::in);
    ss &gt;&gt; shift;
    if (ss.fail() || !ss.eof()) {
        caesar_usage();
        return EXIT_FAILURE;
    }

    // turn off white space skipping
    std::cin &gt;&gt; std::noskipws;

    std::transform(
        std::istream_iterator&lt;char&gt;(std::cin),
        std::istream_iterator&lt;char&gt;(),
        std::ostream_iterator&lt;char&gt;(std::cout), 
        [&amp;](char c) -&gt; char {
          return caesar_cipher(c, shift);
        }
    );

    return EXIT_SUCCESS;
}


Encode | decode:
./caesar 5 &lt;in.txt | ./caesar -5