Skip to content

Broken Type Trait Detecting Minimal Specializations #132

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

Open
mattyclarkson opened this issue Oct 22, 2014 · 4 comments
Open

Broken Type Trait Detecting Minimal Specializations #132

mattyclarkson opened this issue Oct 22, 2014 · 4 comments
Labels
Milestone

Comments

@mattyclarkson
Copy link
Contributor

I tried to specialize the system_clock serialization:

namespace cereal {
template <typename Archive, typename D>
inline
std::string SaveAsValue(const Archive& /*a*/, const std::chrono::time_point<std::chrono::system_clock, D>& duration) {
  return ToIso8601(duration);
}

template <typename Archive, typename D>
inline
void LoadAsValue(const Archive& /*a*/, std::chrono::time_point<std::chrono::system_clock, D>& duration,
    const std::string& value) {
  duration = std::move(FromIso8601(value));
}
template<typename Archive, typename D>
struct specialize<Archive, std::chrono::time_point<std::chrono::system_clock, D>,
  specialization::non_member_load_save_minimal> {};
} // namespace cereal

An the following trait hits:

        static_assert( check::const_valid || !check::exists, "cereal detected an invalid serialization type parameter in non-member load_minimal.  "
            "load_minimal non-member functions must accept their serialization type by non-const reference" );
cereal/details/traits.hpp:824:9: error: static assertion failed: cereal detected an invalid serialization type parameter in non-member load_minimal.  load_minimal non-member functions must accept their serialization type by non-const reference
cereal/details/traits.hpp: In instantiation of ‘struct cereal::traits::detail::has_non_member_load_minimal_wrapper<std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1l, 1000000000l> > >, cereal::PortableBinaryInputArchive, true>’

Which is a false positive. If I comment out that everything compiles fine.

It's something in:

      // See notes from member load_minimal
      template <class T, class A, class U = void>
      struct has_non_member_load_minimal_impl
      {
        template <class TT, class AA>
        static auto test(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME( std::declval<AA const &>(), std::declval<TT&>(), AnyConvert() ), yes() );
        template <class, class>
        static no test( ... );
        static const bool exists = std::is_same<decltype( test<T, A>( 0 ) ), yes>::value;

        template <class TT, class AA, class UU>
        static auto test2(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME( std::declval<AA const &>(), std::declval<TT&>(), NoConvertConstRef<UU>() ), yes() );
        template <class, class, class>
        static no test2( ... );
        static const bool valid = std::is_same<decltype( test2<T, A, U>( 0 ) ), yes>::value;

        template <class TT, class AA>
        static auto test3(int) -> decltype( CEREAL_LOAD_MINIMAL_FUNCTION_NAME( std::declval<AA const &>(), NoConvertRef<TT>(), AnyConvert() ), yes() );
        template <class, class>
        static no test3( ... );
        static const bool const_valid = std::is_same<decltype( test3<T, A>( 0 ) ), yes>::value;
      };

If I add the following, it works fine:

template <typename Archive>
inline
void LoadAsValue(const Archive& /*a*/,
    std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>& duration,
    const std::string& value) {
  duration = std::move(FromIso8601(value));
}

template <typename Archive>
inline
void LoadAsValue(const Archive& /*a*/,
    std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>& duration,
    const std::string& value) {
  duration = std::move(FromIso8601(value));
}

template <typename Archive>
inline
void LoadAsValue(const Archive& /*a*/,
    std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>& duration,
    const std::string& value) {
  duration = std::move(FromIso8601(value));
}

template <typename Archive>
inline
void LoadAsValue(const Archive& /*a*/,
    std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>& duration,
    const std::string& value) {
  duration = std::move(FromIso8601(value));
}

gcc 4.9.1

@AzothAmmo AzothAmmo added the bug label Oct 22, 2014
@AzothAmmo
Copy link
Contributor

Bug is with AnyConvert, which doesn't seem to be able to be able to convert to partially templated types. Small repro:

template <class T> struct A {};
template <class T> int hello( A<T> ) {}

decltype( hello( cereal::traits::detail::AnyConvert() ) ) x; // fails

@AzothAmmo
Copy link
Contributor

Actually it's probably a bug with NoConvertRef which operates in a similar fashion. These types are supposed to selectively implicitly convert to any other type but have problems when the type they are converting to requires template parameters.

The test that fails is the one for const_valid

@mattyclarkson
Copy link
Contributor Author

Yeah, the const_valid is failing. If I comment that out it compiles correctly.

@AzothAmmo
Copy link
Contributor

This will take a while to fix so I'll push it to the next release and note that it is a known issue in the release notes.

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

No branches or pull requests

2 participants