Base64Encoder() = default;
        ~Base64Encoder() = default;

In general, if you want to explicitly provide special member functions, then explicitly provide them all. Others will advise that if you can avoid defining the special member functions, then do so. [Read more here](https://abseil.io/tips/131).

    class Base64Encoder {
    public:
        // ... no default operations declared ...
        const std::string encode(const std::string s) const;

    private:
        // ...

----

        const std::string encode(const std::string s) const;

`std::string` requires `<string>` be included.

`s` is passed by value to `const`, which incurs an unnecessary copy.  Consider using `std::string_view` if you have [tag:c++17]. [Read more here](https://abseil.io/tips/1).

        std::string encode(const std::string_view s) const;

Otherwise, pass by reference to `const`. 

        std::string encode(const std::string& s) const;

----

        constexpr static unsigned char get_base_64_char(ulong number_of_char) {
            return base64_table.at(number_of_char);
        }

`ulong` is not a standard unsigned integer type. If you need a fixed-size integer, consider one of the types from `<cstdint>` (e.g. `std::uint8_t`). For this use-case, I'd just use `std::size_t`. 

Is `number_of_char` a clear description of what the value represents? Would `index` be clearer?

Do you need the bounds checking of `base64_table.at()`?

----

        const static unsigned char next_ascii(size_t current_index, const std::string s, size_t length_of_s);

The first `const` is unnecessary.

`size_t` is not guaranteed by the standard to exist in the global namespace.  Use `std::size_t` and include `<cstddef>`. [Read more here](https://stackoverflow.com/a/36596739/3762339).

----

        const static size_t MINIMAL_B64_STRING_LENGTH = 4;

Consider reserving upper case names for the preprocessor.

`constexpr`?

----

        std::stringstream encoding;

Do we need a `std::stringstream`? We can actually calculate the destination buffer length.  For base64 encoding, every 3 octets maps to 4 sextets.  To find the encoded length \$m\$, find the total number of octets to be read (integral ceiling) and multiply it by the length of each sextet.

$$m = 4 \dot ((n + 2) / 3)$$

----

        while (i < length_of_s) {
            // if first sextet, ...
            // else if second sextet, ...
            // else if third sextet, ...
            // else must be fourth sextet ...
        }

Instead of cycling through each branch on every loop, consider a modulo approach.  Loop through full sextets until you have a partial sextet left at the end (the remainder). Then you can branch based on what you have left.

        
        for (auto remaining_sextets = s.size() / 3; remaining_sextets--;) {
            encoded += /* first sextet masked and shifted */
            encoded += /* second sextet masked and shifted */
            encoded += /* third sextet masked and shifted */
            encoded += /* fourth sextet masked and shifted */
        }

        switch (len % 3) {
        case 2:
            encoded += /* first sextet masked and shifted */
            encoded += /* second sextet masked and shifted */
            encoded += /* third sextet masked and shifted */
            encoded += '=';
            break;
        case 1:
            encoded += /* first sextet masked and shifted */
            encoded += /* second sextet masked and shifted */
            encoded += '=';
            encoded += '=';
            break;
        case 0:
            break;
        }

        return encoded;