I would do it using a random idea of selecting between types compile
time. Like that:
#include <iostream> // I/O of current garbage
#include <type_traits> // std::conditional
#include <cassert> // old school assert
// just classes for demoing
enum Direction {Error, Decrypt, Encrypt};
struct Encryption {Encryption() {std::cout << "Encryption made\n";} };
struct Decryption { Decryption() {std::cout << "Decryption made\n";} };
struct Disaster { Disaster() {assert(not "Disaster useful");} };
template<Direction D>
using Transformation = std::conditional<D == Decrypt, Decryption
, typename std::conditional<D == Encrypt, Encryption
, Disaster
>::type>::type;
int main()
{
Transformation<Encrypt> a;
Transformation<Decrypt> b;
Transformation<Error> c;
}
Trying on gcc version 9.2.0 gave that (did not try elsewhere):
a.out: main.cpp:9: Disaster::Disaster(): Assertion `not "Disaster useful"' failed.
Encryption constructed
Decryption constructed
bash: line 7: 15254 Aborted (core dumped) ./a.out