5

I've already asked this question on github (about a month ago), without any answer so I'm asking here now.

I'm using Cereal as a serialization library in my project. I've tried to add serialization functionality for std::string_view (which is basically copy & paste from the std::string implementation). However, Cereal throws a compiler error:

cereal could not find any output serialization functions for the provided type and archive combination.

Here is my implementation (I disabled deserialization here, but I've also tried a dummy function which gave me the same result):

#pragma once

#include "../cereal.hpp"

#include <string_view>

namespace cereal
{
    //! Serialization for basic_string_view types, if binary data is supported
    template <class Archive, class CharT, class Traits>
    typename std::enable_if<traits::is_output_serializable<BinaryData<CharT>, Archive>::value, void>::type
    CEREAL_SAVE_FUNCTION_NAME(Archive& ar, std::basic_string_view<CharT, Traits> const& str)
    {
        // Save number of chars + the data
        ar(make_size_tag(static_cast<size_type>(str.size())));
        ar(binary_data(str.data(), str.size() * sizeof(CharT)));
    }


    //! Deserialization into std::basic_string_view is forbidden due to its properties as a view.
    //! However std::basic_string_view can be deserialized into a std::basic_string.
    // template <class Archive, class CharT, class Traits>
    // void CEREAL_LOAD_FUNCTION_NAME(Archive& ar, std::basic_string_view<CharT, Traits> & str);
}

Minimal example:

#include <iostream>
#include <cereal/string_view>  

int main() 
{
    /*
     * Working archive types are:
     *  - BinaryOutputArchive
     *  - PortableBinaryOutputArchive
     *
     * Compiler errors for:
     *  - JSONOutputArchive
     *  - XMLOutputArchive
     */
    using OutputArchive = cereal::JSONOutputArchive;

    std::string_view str = "Hello World!";

    {
        OutputArchive oar(std::cout);
        oar(str);
    }

    return 0;
}

The test successfully compiles and passes for binary archives, but not for XML and JSON serialization.

I assume this has something to do with the trait in the enable_if condition is_output_serializable<BinaryData<CharT>, Archive>, but the trait is also present in the std::string implementation and works perfectly fine. I also couldn't find a second definition or specialization for std::string.

Why do I get that compiler error for XML and JSON archives?

Timo
  • 9,269
  • 2
  • 28
  • 58
  • 1
    I have never used this library, but let me guess. You added serializer only for binary data, but JSON/XML is not designed to store binary data and most likely it expects some string (`char*`?) data serializer. There must be some generic `save` overload which handles string data that you are missing. So trait `is_output_serializable, Archive>` works as expected and you have to provide one for `StringData` trait (if it exists). – R2RT May 05 '19 at 20:07
  • 1
    Naive glancing at JSON archive code suggests it has built in support for `std::string`: https://github.com/USCiLab/cereal/blob/51cbda5f30e56c801c07fe3d3aba5d7fb9e6cca4/include/cereal/archives/json.hpp#L245 – R2RT May 05 '19 at 20:12
  • 1
    Sorry for so many comments, cannot edit anymore. Line 946 defines built-in std::string support: https://github.com/USCiLab/cereal/blob/51cbda5f30e56c801c07fe3d3aba5d7fb9e6cca4/include/cereal/archives/json.hpp#L946 – R2RT May 05 '19 at 20:30
  • @R2RT Good catch, I didn't check the archive implementations. If you wrap your comments up in an answer I'll be happy to accept it. – Timo May 06 '19 at 19:49
  • done. Please let me know if example code compiles, I don't have an environment to check it. – R2RT May 06 '19 at 20:27

1 Answers1

3

As std::string support for JSON and XML serializer is built it, it cannot be found in cereal/types/string.hpp header.

You have to manually add support for string data just as you did for binary data.

I am not experienced in cereal library, but in docs there is example for archive specializations for std::map<std::string, std::string>: http://uscilab.github.io/cereal/archive_specialization.html

It uses a little bit different SFINAE technique and cereal specific traits (is_text_archive, check bottom of the very same article).

Given that, for your code it gives:

namespace cereal
{
template <class Archive, class CharT, class Traits,
            traits::EnableIf<traits::is_text_archive<Archive>::value> = traits::sfinae> inline
void save( Archive & ar, std::basic_string_view<CharT, Traits> const & str )
{
    /// ...
}
}

Note: docs use cereal::traits::DisableIf<cereal::traits::is_text_archive<Archive>::value> to specify binary output specialization. It would be more consistent to use it in place of is_output_serializable<BinaryData<CharT>,...>

R2RT
  • 2,061
  • 15
  • 25