I have a function that does a base 64 encode using Boost. It takes two template parameters: One for the type of container used for input, and one for the type of container used for output. This allows you to do things like provide binary data using a std::vector
but get a std::string
back.
Here's the code:
template<typename OutputContainer, typename InputContainer>
OutputContainer Encode(InputContainer const& data)
{
using namespace boost::archive::iterators;
using base64_it = base64_from_binary<transform_width<
typename InputContainer::const_iterator, 6, 8>>;
OutputContainer result(base64_it(data.begin()), base64_it(data.end()));
static std::string const padding[] { "", "==", "="};
auto const& pad = padding[data.size() % 3];
result.insert(result.end(), pad.begin(), pad.end());
return result;
}
Usage example:
std::string data = "Hello World!+";
auto encoded = Encode<std::string>(data);
Live sample here
Note in the example above, I still had to provide the template argument for the output container even though it's the same type as the input container. In these scenarios, I'd like the OutputContainer
template parameter to be optional and instead use the type deduced by InputContainer
. I am not sure what workarounds or adjustments I can perform to get this kind of interface, but it would be nice to see what SO community can come up with.
Note I am also open to a more iterator-centric approach, but I avoided it due to redundancy/boilerplate (I think it's simpler to pass in containers than iterators). If it ends up looking like the 4-argument version of std::transform()
I think I'll be a lot less satisfied with the solution.