Implementation, Ceaser Cipher in C++
Your functions are doing too much. Remember: one function, one responsibility. That is, the encode function actually both encodes and decodes and that behavior is controlled via its arguments. In particular, the choice of behavior is offloaded to shiftF based on a char. There is no error if that char is anything other than 'd' or 'e'. This is something that we should absolutely try to avoid: we want to catch as many problems as we can at compile-time, but even runtime errors are preferred to silent errors!

On closer inspection, there is no need for such a complication. In fact, the only difference between encoding and decoding is the sign of shift. So we could write:

std::string encode(const std::string&amp; str, int shift)
{
    std::string tempMsg;

    std::transform(str.cbegin(), str.cend(), std::back_inserter(tempMsg), [&amp;](char ch) -&gt; char
    { 
        if (isspace(ch))
            return ' ';

        return ch == 'z' || ch == 'Z' ? ch - 25 : ch + shift; 
    });

    return tempMsg;
}

std::string decode(const std::string&amp; str, int shift)
{
    return encode(str, -1 * shift);
}


What is happening here?


We pass the input message str as a const-ref and not by-value as in your original code. When you pass by-value, the object gets copied and in this case there is no reason for it. In this case, you could actually even pass the object by-reference only, and modify it in-place but we're not doing it here.
We use a standard function std::transform with a lambda function that encapsulates the logic of shiftF. You need to include &lt;algorithm&gt; for this use.
The third argument for std::transform is std::back_inserter found from &lt;iterator&gt;, which takes care of inserting at the back of the string tempMsg.
Conceptually, the division of encoding and decoding into separate functions is cleaner and more logical. Whenever you can implement another function in terms of other functions, it's likely a good idea because you don't have to repeat yourself leading to less maintenance decreasing the chances for bugs.


Once you adopt this approach, you can get rid of the const char variables from your main program, and just call the correct encode or decode function inside your if-statement. As a side remark, you could also return meaningful error codes in your main. For example, if the choice is invalid, return from the else-branch e.g., EXIT_FAILURE.