Skip to content

Type traits for load_minimal use incorrect archive when looking up save_minimal return type #79

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
DrAWolf opened this issue Mar 24, 2014 · 4 comments

Comments

@DrAWolf
Copy link

DrAWolf commented Mar 24, 2014

I still think that the following is relevant for others besides me

I want to serialize enums to strings for text archives, while for binary I want to use standard serialization as an int.
(For my own classes, I want to define a standard serialization, but as soon as I define a string serialization, I want it to be applied for all text archives, while for binary the standard is applied.)

After trying for 2h, I gave up.
Could you come up with a convenient way to do this?

@AzothAmmo
Copy link
Contributor

Right now since enums are still getting pulled in by default you'd have to write something like this:

namespace cereal
{
  template <class T> inline
  typename std::enable_if<common_detail::is_enum<T>::value, std::string>::type
  save_minimal( JSONOutputArchive const &, T const & t )
  {
    // somehow convert t to a string
  }

  template <class T> inline
  typename std::enable_if<common_detail::is_enum<T>::value, void>::type
  load_minimal( JSONInputArchive const &, T && t, std::string const & value )
  {
    // somehow convert value into t
  }
}

Unfortunately you have to specialize explicitly for each archive type because the generic version of the enum serialization takes the archive as a template parameter, so you need to come up with an overload that has higher precedence (and writing another template with some enable_if will have the same precedence).

This is the general game you play with all serialization functions - there can only be one highest priority valid overload for each archive-type pairing.

You also need to put this in the cereal namespace so that the compiler can find it properly.

@DrAWolf
Copy link
Author

DrAWolf commented Mar 27, 2014

I cannot/dontwanto do it globally (i.e. for all enums), so defined the following:
non-binary : save as string
binary : save as fundamental type

#define _AW_ENUM_SERIALIZATION( identifier, enum_type )                                                             \
    template<class Archive>                                                                                         \
    typename std::enable_if<!std::is_same<Archive, cereal::BinaryOutputArchive>::value, std::string >::type         \
    save_minimal( const Archive& archive, const identifier& x )                                                     \
    {                                                                                                               \
        return EnumToString( x );                                                                                   \
    }                                                                                                               \
                                                                                                                    \
    template<class Archive>                                                                                         \
    typename std::enable_if<!std::is_same<Archive, cereal::BinaryInputArchive>::value, void >::type                 \
    load_minimal( const Archive& archive, identifier& x, const std::string& string_rep )                            \
    {                                                                                                               \
        x = StringToEnum( string_rep );                                                                             \
    }                                                                                                               \
                                                                                                                    \
    template<class Archive>                                                                                         \
    typename std::enable_if<std::is_same<Archive, cereal::BinaryOutputArchive>::value, enum_type >::type            \
    save_minimal( const Archive& archive, const identifier& x )                                                     \
    {                                                                                                               \
        return static_cast<enum_type>( x );                                                                         \
    }                                                                                                               \
                                                                                                                    \
    template<class Archive>                                                                                         \
    typename std::enable_if<std::is_same<Archive, cereal::BinaryInputArchive>::value, void >::type                  \
    load_minimal( const Archive& archive, identifier && x,  const enum_type& value )                                \
    {                                                                                                               \
        x = reinterpret_cast<identifier>( value );                                                                  \
    }                                                                                                               \

UNFORTUNATELY, I get a compiler error - which I think is NOT CORRECT.
"error C2338: cereal detected different types in corresponding non-member load_minimal and save_minimal functions. the paramater to load_minimal must be a constant reference to the type that save_minimal returns.
"
If I only use one version (without the enable_ifs), it works fine, but I dont want to save enums as string in the binary case)
Might be a conflict with the enum load/save_minimal in common.hpp.
Maybe your checks also compare the standard (common.hpp) save_minimal with my specializations?

@AzothAmmo
Copy link
Contributor

There's a bug in our type traits that look up the return type of save_minimal. It's passing the input archive to the type trait instead of the the output archive, so it is finding one of the incorrect overloads for your functions and taking its return type.

@AzothAmmo AzothAmmo added the bug label Mar 27, 2014
@AzothAmmo AzothAmmo changed the title Saving enums (and user classes) as std::string for text archives only Type traits for load_minimal use incorrect archive when looking up save_minimal return type Mar 27, 2014
@AzothAmmo AzothAmmo added this to the v1.1.0 milestone Apr 18, 2014
AzothAmmo added a commit that referenced this issue May 22, 2014
Added a set of trait classes that can be used to get an input archive
from an output archive.  Requires specializing a struct for each direction or
alternatively using the new macro CEREAL_SETUP_ARCHIVE_TRAITS(InArchive, OutArchive).
This has already been added for all built in archive types.  This is currently only
used for minimal serialization.

load_minimal type traits now correctly use the output archive to check the existence of
a corresponding save_minimal and get its return type, using the new get_input_from_output
type class.

Added a test for this case into the minimal structs test.

Sandbox_vs needed the new macro to become compliant.
@AzothAmmo
Copy link
Contributor

Should be good to go now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants