Cereal serialisation issue for std::chrono with dynamic library - c++11

I have a problem with cereal library (http://uscilab.github.io/cereal/).
I have a shared library, and I would like to serialize one of its classes using cereal library. It has a member of time_point from std::chrono
Here is a part of the code of my object in Event.h
#include <cereal/types/chrono.hpp>
#include <cereal/types/string.hpp>
class Event
{
private:
std::string m_Id;
std::chrono::high_resolution_clock::time_point m_StartTime;
public:
template<class Archive> void serialize(Archive & archive)
{
archive(m_Id, m_StartTime);
}
The library compiles without a problem. Then I would like to use my library in an executable where I try to serialize one of the object:
#include "Event.h"
#include <cereal/archives/json.hpp>
cereal::JSONOutputArchive output(std::cout);
output(API::Event());
This code does not compile and it is complaining about the missing serialize function for the time_point. If I intend to serialize only the string it compiles.
Build error output:
[ 20%] Building CXX object CMakeFiles/plugin.dir/src/main.cpp.o
In file included from /cereal/include/cereal/types/memory.hpp:33:0,
from main.cpp:7:
cereal/include/cereal/cereal.hpp: In instantiation of ‘ArchiveType&
cereal::OutputArchive<ArchiveType, Flags>::processImpl(const T&) [with T = std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >; typename cereal::traits::detail::EnableIfHelper<(cereal::traits::has_invalid_output_versioning<T, ArchiveType>::value || ((! cereal::traits::is_output_serializable<T, ArchiveType>::value) && ((!(Flags & AllowEmptyClassElision)) || ((Flags & AllowEmptyClassElision) && (! std::is_empty<T>::value)))))>::type <anonymous> = (cereal::traits::detail::type)0; ArchiveType = cereal::JSONOutputArchive; unsigned int Flags = 0]’:
cereal/include/cereal/cereal.hpp:347:9: required from ‘void cereal::OutputArchive<ArchiveType, Flags>::process(T&&) [with T = std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >&; ArchiveType = cereal::JSONOutputArchive; unsigned int Flags = 0]’
cereal/include/cereal/cereal.hpp:249:9: required from ‘ArchiveType& cereal::OutputArchive<ArchiveType, Flags>::operator()(Types&& ...) [with Types = {std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >&}; ArchiveType = cereal::JSONOutputArchive; unsigned int Flags = 0]’
Event.h:66:16: required from ‘void Event::serialize(Archive&) [with Archive = cereal::JSONOutputArchive]’
cereal/include/cereal/access.hpp:243:51: required from ‘static decltype (t.serialize(ar)) cereal::access::member_serialize(Archive&, T&) [with Archive = cereal::JSONOutputArchive; T = Event; decltype (t.serialize(ar)) = void]’
cereal/include/cereal/cereal.hpp:400:33: required from ‘ArchiveType& cereal::OutputArchive<ArchiveType, Flags>::processImpl(const T&) [with T = Event; typename cereal::traits::detail::EnableIfHelper<cereal::traits::has_member_serialize<T, ArchiveType>::value, (! cereal::traits::has_invalid_output_versioning<T, ArchiveType>::value), (cereal::traits::is_output_serializable<T, ArchiveType>::value && (cereal::traits::is_specialized_member_serialize<T, ArchiveType>::value || (! cereal::traits::is_specialized<T, ArchiveType>::value)))>::type <anonymous> = (cereal::traits::detail::type)0; ArchiveType = cereal::JSONOutputArchive; unsigned int Flags = 0]’
cereal/include/cereal/cereal.hpp:347:9: required from ‘void cereal::OutputArchive<ArchiveType, Flags>::process(T&&) [with T = Event; ArchiveType = cereal::JSONOutputArchive; unsigned int Flags = 0]’
cereal/include/cereal/cereal.hpp:249:9: required from ‘ArchiveType& cereal::OutputArchive<ArchiveType, Flags>::operator()(Types&& ...) [with Types = {Event}; ArchiveType = cereal::JSONOutputArchive; unsigned int Flags = 0]’
main.cpp:38:36: required from here
cereal/include/cereal/cereal.hpp:462:9: error: static assertion failed: cereal could not find any output serialization functions for the provided type and archive combination.
EDIT:
I guess the problem is coming from the fact that the serialization function is defined in the shared library.
If I just compile a test class (not in my project just for test) having an time_point it works as expected.

It looks like it was due to the order of the include. The include of the archives must be before the include of the types/chrono. So the right order is:
#include <cereal/archives/json.hpp>
#include "Event.h"
cereal::JSONOutputArchive output(std::cout);
output(API::Event());

Related

c++ - is it possible to create an optional promise?

consider the following code:
#include <future>
#include <boost/optional.hpp>
struct S {
std::promise<int> p;
};
void f() {
boost::optional<S> o = std::move(S());
}
it fails to compile because somewhere deep inside boost::optional implementation it tries to use the copy constructor of S.
is there some way to overcome this and move the promise without copying it?
I tried to explicitly add a move constructor to S
S(S&& s): p(std::move(s.p)) {}
S() = default;
to no avail.
compiler error message:
In file included from /usr/include/boost/optional.hpp:15:0,
from /tmp/iotpromise.cpp:2:
/usr/include/boost/optional/optional.hpp: In instantiation of ‘void boost::optional_detail::optional_base<T>::construct(boost::optional_detail::optional_base<T>::argument_type) [with T = S; boost::optional_detail::optional_base<T>::argument_type = const S&]’:
/usr/include/boost/optional/optional.hpp:230:20: required from ‘boost::optional_detail::optional_base<T>::optional_base(boost::optional_detail::optional_base<T>::argument_type) [with T = S; boost::optional_detail::optional_base<T>::argument_type = const S&]’
/usr/include/boost/optional/optional.hpp:526:46: required from ‘boost::optional<T>::optional(boost::optional<T>::argument_type) [with T = S; boost::optional<T>::argument_type = const S&]’
/tmp/iotpromise.cpp:9:39: required from here
/usr/include/boost/optional/optional.hpp:346:8: error: use of deleted function ‘S::S(const S&)’
new (m_storage.address()) internal_type(val) ;
^
/tmp/iotpromise.cpp:4:8: note: ‘S::S(const S&)’ is implicitly deleted because the default definition would be ill-formed:
struct S {
^
/tmp/iotpromise.cpp:4:8: error: use of deleted function ‘std::promise<_Res>::promise(const std::promise<_Res>&) [with _Res = int]’
In file included from /tmp/iotpromise.cpp:1:0:
/usr/include/c++/4.9/future:977:7: note: declared here
promise(const promise&) = delete;
^
Using Boost 1.55.0, GCC 6.3

Unable to compare std::chrono::duration with zero

In a template class I am working on, I want to check a precondition that a std::chrono::duration is positive, but my compiler complains that it can not instantiate the needed operator< template.
Here is a minimal example (not my original container) of the problem:
#include <chrono>
#include <cassert>
#undef NDEBUG
template< typename VALUE >
class Container final
{
public:
using Interval = std::chrono::duration< unsigned int >;
Container(const Interval interval_):
interval(interval_),
value(0)
{
assert(Interval::zero < interval_);
}
private:
Interval interval;
VALUE value;
};
template class Container< unsigned int >;
The compiler complains about the assert statement, thus:
In file included from /usr/include/c++/6/cassert:44:0,
from main.cpp:2:
main.cpp: In constructor ‘Container<VALUE>::Container(Container<VALUE>::Interval)’:
main.cpp:15:29: error: no match for ‘operator<’ (operand types are ‘std::chrono::duration<unsigned int>()’ and ‘const Interval {aka const std::chrono::duration<unsigned int>}’)
assert(Interval::zero < interval_);
~~~~~~~~~~~~~~~^~~
In file included from main.cpp:1:0:
/usr/include/c++/6/chrono:668:7: note: candidate: template<class _Clock, class _Dur1, class _Dur2> constexpr bool std::chrono::operator<(const std::chrono::time_point<_Clock, _Duration1>&, const std::chrono::time_point<_Clock, _Duration2>&)
operator<(const time_point<_Clock, _Dur1>& __lhs,
^~~~~~~~
/usr/include/c++/6/chrono:668:7: note: template argument deduction/substitution failed:
In file included from /usr/include/c++/6/cassert:44:0,
from main.cpp:2:
main.cpp:15:31: note: mismatched types ‘const std::chrono::time_point<_Clock, _Duration1>’ and ‘std::chrono::duration<unsigned int>()’
assert(Interval::zero < interval_);
^
In file included from main.cpp:1:0:
/usr/include/c++/6/chrono:489:7: note: candidate: template<class _Rep1, class _Period1, class _Rep2, class _Period2> constexpr bool std::chrono::operator<(const std::chrono::duration<_Rep1, _Period1>&, const std::chrono::duration<_Rep2, _Period2>&)
operator<(const duration<_Rep1, _Period1>& __lhs,
^~~~~~~~
/usr/include/c++/6/chrono:489:7: note: template argument deduction/substitution failed:
In file included from /usr/include/c++/6/cassert:44:0,
from main.cpp:2:
main.cpp:15:31: note: mismatched types ‘const std::chrono::duration<_Rep1, _Period1>’ and ‘std::chrono::duration<unsigned int>()’
assert(Interval::zero < interval_);
What have I done wrong?
Or is this a compiler bug? My compiler is g++ (Debian 6.3.0-18+deb9u1) 6.3.0 2017051, on Debian 6.
Try with Interval::zero(). Interval::zero is a function, so you are comparing a duration with a function.
As a side note, I would suggest to make your Interval argument in the constructor a template, so that you can accept other duragion scales (seconds, ms, us, etc.)
template < typename Interval2 >
explicit Container(const Interval2 interval_):
interval(interval_),
value(0)
{
assert(Interval2::zero() < interval_);
}
The std::chrono::duration constructor will adapt the tick count transparently, following both Period parameter types.

C++11 class in std::map as Value with private constructors

Here is the simplified version of the class which is stored as value in a map which works fine in VS2008 (note that all members are private):
class Value{
friend class FriendClass;
friend class std::map<std::string, Value>;
friend struct std::pair<const std::string, Value>;
friend struct std::pair<std::string, Value>;
Value() {..}
Value(Value const& other) {..}
... rest members...
};
Code (called from FriendClass, so this can reach private constructors) :
FriendClass::func()
{
std::map<const std::string, Value> map;
map.insert(std::make_pair(std::string("x"), Value()));
}
This compiles w/o any error in VS2008, but fails on VS2015/C++11:
file.cpp(178): error C2664: 'std::_Tree_iterator>>> std::_Tree>::insert(std::_Tree_const_iterator>>>,const std::pair &)': cannot convert argument 1 from 'std::pair' to 'std::pair &&'
with
[
_Kty=std::string,
_Ty=Value,
_Pr=std::less,
_Alloc=std::allocator>
]
and
[
_Kty=std::string,
_Ty=Value
]
file.cpp(178): note: Reason: cannot convert from 'std::pair' to 'std::pair'
with
[
_Kty=std::string,
_Ty=Value
]
file.cpp(178): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
If I make the Value copy constructor public, it compiles fine in VS2015 as well. But that was private with purpose, and only made available for std::map and std::pair. However, it seems in C++11 additional friend access are also necessary to declare. Which are these?
Thank you.
I don't have access to the compilers you mentioned, but here's what I'm seeing on g++ 5.3.
Consider the following essentially-same version of your question:
#include <map>
#include <utility>
class foo
{
friend std::pair<const int, foo>;
foo(const foo &other){}
public:
foo(){}
};
int main()
{
using map_t = std::map<int, foo>;
map_t m;
m.insert(std::make_pair(2, foo()));
// m.emplace(2, foo());
}
(The default ctor is public, but that's non-essential and just makes the example shorter.)
In main, note the two lines
m.insert(std::make_pair(2, foo()));
// m.emplace(2, foo());
Reversing the comments builds fine, but the version shown doesn't:
/usr/include/c++/5/bits/stl_pair.h: In instantiation of ‘constexpr std::pair<_T1, _T2>::pair(_U1&&, const _T2&) [with _U1 = int; <template-parameter-2-2> = void; _T1 = int; _T2 = foo]’:
/usr/include/c++/5/bits/stl_pair.h:281:72: required from ‘constexpr std::pair<typename std::__decay_and_strip<_Tp>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&) [with _T1 = int; _T2 = foo; typename std::__decay_and_strip<_T2>::__type = foo; typename std::__decay_and_strip<_Tp>::__type = int]’
stuff.cpp:21:34: required from here
stuff.cpp:9:2: error: ‘foo::foo(const foo&)’ is private
foo(const foo &other){}
^
Looking at the source code std_pair.h shows that indeed it is trying to call the copy constructor. Unfortunately, you friended std::pair, but not std::make_pair.
The emplace version doesn't have this problem, but I suspect that this is implementation dependent. In general, if you want a container to store a completely opaque class, I would suggest that you use a container of std::shared_ptrs to them. This allows you to completely specify which function/class can create/copy objects in your own code, and makes no assumptions on the library's code.

g++ fails to look up static functions in a template class, is it a bug or standard defined?

When I try some C++11 code like following, it passed in all clang++ available to me that support C++11, but it failed to compile in g++-4.8, g++-4.9 and g++-5.0.
#include <type_traits>
#include <vector>
template <class C, class First, class Last>
struct HasInsertEnd {
template <class U>
static std::false_type Check(...);
template <class U>
static auto Check(U val)
-> decltype(val.insert(val.end(), std::declval<First>(),
std::declval<Last>()),
std::true_type{});
template <class U>
using Deduce = decltype(Check<U>(std::declval<U>()));
using type = typename Deduce<C>::type;
static constexpr bool value = type::value;
};
int main(int argc, char* argv[]) {
static_assert(!HasInsertEnd<int, int, int>::value, "...");
static_assert(HasInsertEnd<std::vector<int>, const int*, const int*>::value,
"...");
return 0;
}
g++ will report errors like:
‘Check’ was not declared in this scope
If I change the calling of Check in the Deduce to HasInsertEnd::Check, both g++ and clang++ will be happy.
I know little about dependent name lookup. The problem is, which behavior is standard?
This is a bug in GCC, and can be shown to be a bug in GCC even without deferring to the standard.
template <typename T>
struct f { typedef int type; };
template <typename T>
struct S {
template <typename U>
static f<U> f();
template <class U>
using u = typename decltype(f<U>())::type;
using t = u<T>;
};
S<int>::t main() { }
This is rejected the same way in GCC 4.7.4 and GCC 5, with "error: ‘f’ was not declared in this scope". That's just nonsense. Even if the static member function should somehow not be visible, there is still a global type by the same name that would be found instead. It gets even better, though: with that global type, you get:
test.cc: In substitution of ‘template<class T> template<class U> using u = typename decltype (f<U>())::type [with U = T; T = T]’:
test.cc:12:20: required from here
test.cc:10:36: error: ‘f’ was not declared in this scope
using u = typename decltype(f<U>())::type;
^
test.cc:10:36: note: suggested alternative:
test.cc:2:12: note: ‘f’
struct f { typedef int type; };
^
test.cc:15:13: error: ‘t’ in ‘struct S<int>’ does not name a type
S<int>::t main() { }
^
That's right, it's suggesting that f can be corrected by spelling it f.
I don't see any problem with your code, and if it isn't a known bug, I encourage you to report it. and it's been reported as a bug before.
Oddly, as noted in the comments, GCC 4.8.4 and GCC 4.9.2 do find a global f. However, if the global f is a type, then they still reject the program, with "error: missing template arguments" even though the template argument is provided, so it's still clearly a bug in GCC.

Cilk++ with Boost Library

I am facing an issue while compiling the Cilk++ code with Boost Library.
The Boost Library has been installed outside /usr/include.
I used a -I option to specify the boost directory while compiling with cilk++. I am getting the following error.
/home/user/boost_1_51_0/boost/multi_array.hpp: In member function
‘boost::multi_array<T, NumDims, Allocator>& cilk boost::multi_array<T,
NumDims, Allocator>::resize(const
boost::detail::multi_array::extent_gen<NumDims>&) [with T = float,
long unsigned int NumDims = 2ul, Allocator = std::allocator<float>]’:
kdtree2.h:95: instantiated from here
/home/user/boost_1_51_0/boost/multi_array.hpp:415: error: no matches
converting function ‘min’ to type ‘const
boost::multi_array_types::size_type& (cilk*)(const
boost::multi_array_types::size_type&, const
boost::multi_array_types::size_type&)’
/home/user/cilk/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.2.4/../../../../include/c++/4.2.4/bits/stl_algobase.h:182:
error: candidates are: template<class _Tp> const _Tp& std::min(const
_Tp&, const _Tp&) /home/user/cilk/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.2.4/../../../../include/c++/4.2.4/bits/stl_algobase.h:226:
error: template<class _Tp, class _Compare> const _Tp& std::min(const
_Tp&, const _Tp&, _Compare)
The issue got resolved by using the -isystem option during compilation.

Resources