I am chasing a rabbit down the hole, by trying to figure out the following:
I do not want empty public constructors (they can, and will create issues)
Two template classes must remain ignorant of each-other, else I will have template parameter cyclic problems
A third class apparently needs access to both previous classes, as it is the one that is being (de)serialized
A minified example is shown below:
template <class s_trait>
class state
{
public:
state(s_trait);
private:
state() = default;
friend class boost::serialization::access;
template <typename archive>
void serialize(archive &, const unsigned int);
};
template <class a_trait>
class action
{
public:
action(a_trait);
private:
action() = default;
friend class boost::serialization::access;
template <typename archive>
void serialize(archive &, const unsigned int);
};
template <class state_type, class action_type>
class policy
{
public:
/// ... some public methods
private:
friend class boost::serialization::access;
std::unordered_map<state_class,
std::unordered_map<action_class,
double>> __policies__;
template <typename archive>
void serialize(archive &, const unsigned int);
};
The above skeleton (without the boring details) has the following design issues:
class state cannot be aware of action, if action is to be aware of state
class action cannot be aware of state and vice versa
class policy templates the state and action on purpose
However, compiling an app using those classes creates issues arising from std::pair, which seem to stem from boost::serialization::access, which in turn appear to be from the fact that class policy needs access to the default empty constructors when calling serialize:
/usr/include/c++/5/bits/stl_pair.h: In instantiation of ‘constexpr std::pair<_T1, _T2>::pair() [with _T1 = const relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >; _T2 = std::unordered_map<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double, relearn::hasher<relearn::action<mu
mbler::action<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::allocator<std::pair<const relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double> > >]’:
/usr/include/boost/serialization/access.hpp:132:9: required from ‘static void boost::serialization::access::construct(T*) [with T = std::pair<const relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, std::unordered_map<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double, rel
earn::hasher<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::allocator<std::pair<const relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double> > > >]’
/usr/include/boost/serialization/serialization.hpp:93:22: required from ‘void boost::serialization::load_construct_data(Archive&, T*, unsigned int) [with Archive = boost::archive::binary_iarchive; T = std::pair<const relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, std::unordered_map<relearn::act
ion<mumbler::action<std::__cxx11::basic_string<char> > >, double, relearn::hasher<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::allocator<std::pair<const relearn::action<mumbler::action<std::__cxx11::b
asic_string<char> > >, double> > > >]’
/usr/include/boost/serialization/serialization.hpp:158:28: required from ‘void boost::serialization::load_construct_data_adl(Archive&, T*, unsigned int) [with Archive = boost::archive::binary_iarchive; T = std::pair<const relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, std::unordered_map<relearn
::action<mumbler::action<std::__cxx11::basic_string<char> > >, double, relearn::hasher<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::allocator<std::pair<const relearn::action<mumbler::action<std::__cxx
11::basic_string<char> > >, double> > > >]’
/usr/include/boost/serialization/detail/stack_constructor.hpp:54:54: required from ‘boost::serialization::detail::stack_construct<Archive, T>::stack_construct(Archive&, unsigned int) [with Archive = boost::archive::binary_iarchive; T = std::pair<const relearn::state<mumbler::state<std::__cxx11::basic_string<char> >
>, std::unordered_map<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double, relearn::hasher<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::allocator<std::pair<const relearn::act
ion<mumbler::action<std::__cxx11::basic_string<char> > >, double> > > >]’
/usr/include/boost/serialization/unordered_map.hpp:45:55: required from ‘void boost::serialization::stl::archive_input_unordered_map<Archive, Container>::operator()(Archive&, Container&, unsigned int) [with Archive = boost::archive::binary_iarchive; Container = std::unordered_map<relearn::state<mumbler::state<std::
__cxx11::basic_string<char> > >, std::unordered_map<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double, relearn::hasher<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::allocator
<std::pair<const relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double> > >, relearn::hasher<relearn::state<mumbler::state<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::state<mumbler::state<std::__cxx11::basic_string<char> > > >, std::allocator<std::pair<const relearn::state<mu
mbler::state<std::__cxx11::basic_string<char> > >, std::unordered_map<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double, relearn::hasher<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >, std::equal_to<relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >
>, std::allocator<std::pair<const relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >, double> > > > > >]’
/usr/include/boost/serialization/unordered_collections_load_imp.hpp:66:14: [ skipping 24 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/archive/detail/iserializer.hpp:618:18: required from ‘void boost::archive::load(Archive&, T&) [with Archive = boost::archive::binary_iarchive; T = relearn::policy<relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, relearn::action<mumbler::action<std::__cxx11::basic_string<char> >
> >]’
/usr/include/boost/archive/detail/common_iarchive.hpp:66:22: required from ‘void boost::archive::detail::common_iarchive<Archive>::load_override(T&, int) [with T = relearn::policy<relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, relearn::action<mumbler::action<std::__cxx11::basic_string<char> > >
>; Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/basic_binary_iarchive.hpp:76:7: required from ‘void boost::archive::basic_binary_iarchive<Archive>::load_override(T&, int) [with T = relearn::policy<relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, relearn::action<mumbler::action<std::__cxx11::basic_string<char> > > >;
Archive = boost::archive::binary_iarchive]’
/usr/include/boost/archive/binary_iarchive_impl.hpp:62:9: required from ‘void boost::archive::binary_iarchive_impl<Archive, Elem, Tr>::load_override(T&, int) [with T = relearn::policy<relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, relearn::action<mumbler::action<std::__cxx11::basic_string<char>
> > >; Archive = boost::archive::binary_iarchive; Elem = char; Tr = std::char_traits<char>]’
/usr/include/boost/archive/detail/interface_iarchive.hpp:60:9: required from ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator>>(T&) [with T = relearn::policy<relearn::state<mumbler::state<std::__cxx11::basic_string<char> > >, relearn::action<mumbler::action<std::__cxx11::basic_string<char> >
> >; Archive = boost::archive::binary_iarchive]’
/home/alex/codez/mumbler/src/agent.cpp:9:11: required from here
/home/alex/codez/mumbler/src/relearn/src/relearn.hpp:90:5: error: ‘relearn::state<state_trait, value_type>::state() [with state_trait = mumbler::state<std::__cxx11::basic_string<char> >; value_type = double]’ is private
state() = default;
As far as I can see, I have two options:
leave a public empty default constructor
forward-declare class policy, then befriend it - however this creates the issue that the classes befriending it need be aware of its template parameters, thus they need to be aware of each-other (state-action) which is what I would like to avoid.
Is there some other way to go around this without exposing public empty constructors?
edit
This is not a duplicate, I know how to (de)serialize, the question is about hiding the default constructor for only the (de)serializer to have access to it.
Make your default constructors protected, then make a derived class from each that has a public constructor but hide those derived classes from the outside entirely (put them in a detail header file that nobody else includes). Then your policy class can use the derived classes internally, for serialization and storage, but only expose them as (sliced) base class objects.
Related
Consider a CGAL::Arrangement_2. Right now, I have to iterate through it like this:
using MyArrangement = CGAL::Arrangement_2<MyTraits, MyDcel>;
for(MyArrangement::Face_handle face = map.faces_begin(); face != map.faces_end(); ++face)
{
do_stuff(face);
}
If I try to migrate this to using a C++11-style range-based for loop like this:
for(auto face : gMap)
{
do_stuff(face)
}
I get the following error (emphasis mine):
Error:(1385, 13) invalid range expression of type 'CGAL::Arrangement_2 > >, true>, std::__1::vector > >, true> >, std::__1::allocator > >, true> > > >, CGAL::Arr_consolidated_curve_data_traits_2 > >, true> >, int> >, CGAL::Arr_extended_dcel > >, true>, std::__1::vector > >, true> >, std::__1::allocator > >, true> > > >, CGAL::Arr_consolidated_curve_data_traits_2 > >, true> >, int> >, GIS_vertex_data, GIS_halfedge_data, GIS_face_data, CGAL::Arr_vertex_base > >, true> > >, CGAL::Gps_halfedge_base > >, true> >, CGAL::_Unique_list > >, CGAL::Gps_face_base> >'; no viable 'begin' function available
The error is the same if I change the for loop to use auto &face or const auto &face.
Does anyone have a workaround for this, or some nice wrapper to make it work? I'm trying to avoid having to resort to using this monstrosity with a lambda argument:
template<typename F>
void for_each_face(MyArrangement &map, F callback)
{
for(MyArrangement::Face_handle f = map.faces_begin(); f != map.faces_end(); ++f)
{
callback(f);
}
}
The range base version to iterate over faces is face_handles(). You have similar functions for vertices(vertex_handles()), and halfedges (halfedge_handles()).
I want to create multi_index_container with type A storing objects of type C, which is derived from B which is derived from A. Problem is that in A I have pure virtual function. When I try to compile it, I got errors which are described at the very bottom.
I guess it's not possible to make-it-right?
Is whole idea flawed?
Code
#include <iostream>
#include <string>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/mem_fun.hpp>
using boost::multi_index_container;
using namespace boost::multi_index;
class A{
public:
virtual void print()=0;
std::string getName() const {return name;};
void setName(std::string s){name=s;};
std::string name;
};
template<typename T>
class B: public A{
public:
virtual void print(){std::cout<<"B"<<name<<std::endl;}
};
template<typename T>
class C: public B<T> {
public:
virtual void print(){std::cout<<"C"<<reinterpret_cast<A*>(this)->name<<std::endl;}
};
typedef multi_index_container<
A,
indexed_by<
hashed_non_unique<const_mem_fun<A, std::string, &A::getName>>
>
> Container;
int main(){
C<int> c;
c.setName("c");
Container container;
container.insert(c);
return 0;
}
Errors
In file included from /usr/local/include/boost/aligned_storage.hpp:20:0,
from /usr/local/include/boost/type_traits/aligned_storage.hpp:11,
from /usr/local/include/boost/multi_index/detail/index_node_base.hpp:17,
from /usr/local/include/boost/multi_index/detail/node_type.hpp:23,
from /usr/local/include/boost/multi_index/detail/index_base.hpp:21,
from /usr/local/include/boost/multi_index/detail/base_type.hpp:21,
from /usr/local/include/boost/multi_index_container.hpp:33,
from wierdInheritance.cpp:13:
/usr/local/include/boost/type_traits/alignment_of.hpp: In instantiation of ‘boost::detail::alignment_of_hack<A>’:
/usr/local/include/boost/type_traits/alignment_of.hpp:71:5: instantiated from ‘const size_t boost::detail::alignment_of_impl<A>::value’
/usr/local/include/boost/type_traits/alignment_of.hpp:89:1: instantiated from ‘boost::alignment_of<A>’
/usr/local/include/boost/multi_index/detail/index_node_base.hpp:42:32: instantiated from ‘boost::multi_index::detail::pod_value_holder<A>’
/usr/local/include/boost/multi_index/detail/index_node_base.hpp:46:8: instantiated from ‘boost::multi_index::detail::index_node_base<A, std::allocator<A> >’
/usr/local/include/boost/multi_index/detail/hash_index_node.hpp:116:8: instantiated from ‘boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<A, std::allocator<A> > >’
/usr/local/include/boost/multi_index/hashed_index.hpp:108:54: instantiated from ‘boost::multi_index::detail::hashed_index<boost::multi_index::const_mem_fun<A, std::basic_string<char>, &A::getName>, boost::hash<std::basic_string<char> >, std::equal_to<std::basic_string<char> >, boost::multi_index::detail::nth_layer<1, A, boost::multi_index::indexed_by<boost::multi_index::hashed_non_unique<boost::multi_index::const_mem_fun<A, std::basic_string<char>, &A::getName> > >, std::allocator<A> >, boost::mpl::vector0<mpl_::na>, boost::multi_index::detail::hashed_non_unique_tag>’
/usr/local/include/boost/multi_index_container.hpp:70:7: instantiated from ‘boost::multi_index::multi_index_container<A, boost::multi_index::indexed_by<boost::multi_index::hashed_non_unique<boost::multi_index::const_mem_fun<A, std::basic_string<char>, &A::getName> > > >’
wierdInheritance.cpp:57:19: instantiated from here
/usr/local/include/boost/type_traits/alignment_of.hpp:42:7: error: cannot declare field ‘boost::detail::alignment_of_hack<A>::t’ to be of abstract type ‘A’
wierdInheritance.cpp:24:7: note: because the following virtual functions are pure within ‘A’:
wierdInheritance.cpp:26:22: note: virtual void A::print()
In file included from /usr/local/include/boost/multi_index_container.hpp:20:0,
from wierdInheritance.cpp:13:
/usr/local/include/boost/detail/allocator_utilities.hpp: In function ‘void boost::detail::allocator::construct(void*, const Type&) [with Type = A]’:
/usr/local/include/boost/multi_index/detail/index_base.hpp:88:5: instantiated from ‘boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::node_type* boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::insert_(boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::value_param_type, boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::node_type*) [with Value = A, IndexSpecifierList = boost::multi_index::indexed_by<boost::multi_index::hashed_non_unique<boost::multi_index::const_mem_fun<A, std::basic_string<char>, &A::getName> > >, Allocator = std::allocator<A>, boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::node_type = boost::multi_index::detail::index_node_base<A, std::allocator<A> >, boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::value_param_type = const A&]’
/usr/local/include/boost/multi_index/hashed_index.hpp:701:63: instantiated from ‘boost::multi_index::detail::hashed_index<KeyFromValue, Hash, Pred, SuperMeta, TagList, Category>::node_type* boost::multi_index::detail::hashed_index<KeyFromValue, Hash, Pred, SuperMeta, TagList, Category>::insert_(boost::multi_index::detail::hashed_index<KeyFromValue, Hash, Pred, SuperMeta, TagList, Category>::value_param_type, boost::multi_index::detail::hashed_index<KeyFromValue, Hash, Pred, SuperMeta, TagList, Category>::node_type*) [with KeyFromValue = boost::multi_index::const_mem_fun<A, std::basic_string<char>, &A::getName>, Hash = boost::hash<std::basic_string<char> >, Pred = std::equal_to<std::basic_string<char> >, SuperMeta = boost::multi_index::detail::nth_layer<1, A, boost::multi_index::indexed_by<boost::multi_index::hashed_non_unique<boost::multi_index::const_mem_fun<A, std::basic_string<char>, &A::getName> > >, std::allocator<A> >, TagList = boost::mpl::vector0<mpl_::na>, Category = boost::multi_index::detail::hashed_non_unique_tag, boost::multi_index::detail::hashed_index<KeyFromValue, Hash, Pred, SuperMeta, TagList, Category>::node_type = boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<A, std::allocator<A> > >, typename SuperMeta::type::node_type = boost::multi_index::detail::index_node_base<A, std::allocator<A> >, boost::multi_index::detail::hashed_index<KeyFromValue, Hash, Pred, SuperMeta, TagList, Category>::value_param_type = const A&]’
/usr/local/include/boost/multi_index_container.hpp:488:40: instantiated from ‘std::pair<typename boost::multi_index::detail::multi_index_base_type<Value, IndexSpecifierList, Allocator>::type::node_type*, bool> boost::multi_index::multi_index_container<Value, IndexSpecifierList, Allocator>::insert_(const Value&) [with Value = A, IndexSpecifierList = boost::multi_index::indexed_by<boost::multi_index::hashed_non_unique<boost::multi_index::const_mem_fun<A, std::basic_string<char>, &A::getName> > >, Allocator = std::allocator<A>, typename boost::multi_index::detail::multi_index_base_type<Value, IndexSpecifierList, Allocator>::type::node_type = boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<A, std::allocator<A> > >]’
/usr/local/include/boost/multi_index/detail/index_base.hpp:150:30: instantiated from ‘std::pair<typename boost::multi_index::detail::multi_index_node_type<Value, IndexSpecifierList, Allocator>::type*, bool> boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::final_insert_(boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::value_param_type) [with Value = A, IndexSpecifierList = boost::multi_index::indexed_by<boost::multi_index::hashed_non_unique<boost::multi_index::const_mem_fun<A, std::basic_string<char>, &A::getName> > >, Allocator = std::allocator<A>, typename boost::multi_index::detail::multi_index_node_type<Value, IndexSpecifierList, Allocator>::type = boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<A, std::allocator<A> > >, boost::multi_index::detail::index_base<Value, IndexSpecifierList, Allocator>::value_param_type = const A&]’
/usr/local/include/boost/multi_index/hashed_index.hpp:254:61: instantiated from ‘std::pair<boost::multi_index::detail::hashed_index_iterator<boost::multi_index::detail::hashed_index_node<typename SuperMeta::type::node_type>, boost::multi_index::detail::bucket_array<typename SuperMeta::type::final_allocator_type> >, bool> boost::multi_index::detail::hashed_index<KeyFromValue, Hash, Pred, SuperMeta, TagList, Category>::insert(boost::multi_index::detail::hashed_index<KeyFromValue, Hash, Pred, SuperMeta, TagList, Category>::value_param_type) [with KeyFromValue = boost::multi_index::const_mem_fun<A, std::basic_string<char>, &A::getName>, Hash = boost::hash<std::basic_string<char> >, Pred = std::equal_to<std::basic_string<char> >, SuperMeta = boost::multi_index::detail::nth_layer<1, A, boost::multi_index::indexed_by<boost::multi_index::hashed_non_unique<boost::multi_index::const_mem_fun<A, std::basic_string<char>, &A::getName> > >, std::allocator<A> >, TagList = boost::mpl::vector0<mpl_::na>, Category = boost::multi_index::detail::hashed_non_unique_tag, typename SuperMeta::type::final_allocator_type = std::allocator<A>, typename SuperMeta::type::node_type = boost::multi_index::detail::index_node_base<A, std::allocator<A> >, boost::multi_index::detail::hashed_index<KeyFromValue, Hash, Pred, SuperMeta, TagList, Category>::value_param_type = const A&]’
wierdInheritance.cpp:58:27: instantiated from here
/usr/local/include/boost/detail/allocator_utilities.hpp:178:3: error: cannot allocate an object of abstract type ‘A’
wierdInheritance.cpp:24:7: note: since type ‘A’ has pure virtual functions
You cannot define a container of A, but you can define a container of pointers (eg. shared_ptr) to A:
typedef multi_index_container<
A *,
indexed_by<
hashed_non_unique<const_mem_fun<A, std::string, &A::getName>>
>
> Container;
or:
typedef multi_index_container<
boost::shared_ptr<A>,
indexed_by<
hashed_non_unique<const_mem_fun<A, std::string, &A::getName>>
>
> Container;
I have a map of map
std::map< int, std::map<string, double> > myMap;
std::map< int, std::map<string, double> >::iterator itr;
Iterating it with:
itr = myMap.find(nodeI);
if (itr == myMap.end())
{
exit(1) ;
}
results in the error:
error: no match for âoperator=â in
âitr = ((const PushList*)this)->PushList::myMap.std::map<:_Key, _Tp, _Compare, _Alloc>::find
[with _Key = int, _Tp = std::map<:std::basic_string<:char, std::char_traits<:char>,
std::allocator<:char> >, double, std::less<:std::basic_string<:char,
std::char_traits<:char>,
std::allocator<:char> > >, std::allocator<:std::pair<:const std::basic_string<:char,
std::char_traits<:char>, std::allocator<:char> >, double> > >, _Compare =
std::less<:int>, _Alloc =
std::allocator<:std::pair<:const int, std::map<:std::basic_string<:char,
std::char_traits<:char>,
std::allocator<:char> >, double, std::less<:std::basic_string<:char,
std::char_traits<:char>,
std::allocator<:char> > >, std::allocator<:std::pair<:const std::basic_string<:char,
std::char_traits<:char>, std::allocator<:char> >, double> > > > >](((const
int&)((const int*)((int*)nodeI))))â
How can I iterate the map of map?
From the error you posted it can be seen that you are doing this from within a class member const function. Is there any chance that myMap happens to be a member of that class? If so, what you want is to use const_iterator instead. You should do it anyways, since you are not expecting to modify the contents of the iterated elements.
#include <iostream>
#include <map>
#include <vector>
template<typename T>
class foo {
public:
foo(T val) : m_Value(val) { };
T get_value() const { return m_Value; };
void set_value(const T& t) { m_Value=t; };
bool operator<(const foo<T>& x) { return x.get_value() < m_Value; };
bool operator==(const foo<T>& x) { return x.get_value() == m_Value; };
private:
T m_Value;
};
template<typename T>
class bar {
public:
bar() { };
void print_first() const {
typename std::map<foo<T>,std::vector<foo<T> > >::iterator it;
it = m_Map.begin(); //ERROR!
std::cout << it->first.get_value() << std::endl;
};
private:
std::map<foo<T>,std::vector<foo<T> > > m_Map;
};
int main() {
bar<int> b;
b.print_first();
return 0;
};
I am trying to write a container, but the member functions require use of an iterator, but when I try to actually use an iterator, I get an error:
testcase.cpp: In member function `void bar<T>::print_first() const [with T =
int]':
testcase.cpp:33: instantiated from here
testcase.cpp:24: error: no match for 'operator=' in 'it = std::map<_Key, _Tp,
_Compare, _Alloc>::begin() const [with _Key = foo<int>, _Tp =
std::vector<foo<int>, std::allocator<foo<int> > >, _Compare =
std::less<foo<int> >, _Alloc = std::allocator<std::pair<const foo<int>,
std::vector<foo<int>, std::allocator<foo<int> > > > >]()'
/usr/include/c++/3.3.3/bits/stl_tree.h:184: error: candidates are:
std::_Rb_tree_iterator<std::pair<const foo<int>, std::vector<foo<int>,
std::allocator<foo<int> > > >, std::pair<const foo<int>,
std::vector<foo<int>, std::allocator<foo<int> > > >&, std::pair<const
foo<int>, std::vector<foo<int>, std::allocator<foo<int> > > >*>&
std::_Rb_tree_iterator<std::pair<const foo<int>, std::vector<foo<int>,
std::allocator<foo<int> > > >, std::pair<const foo<int>,
std::vector<foo<int>, std::allocator<foo<int> > > >&, std::pair<const
foo<int>, std::vector<foo<int>, std::allocator<foo<int> > >
>*>::operator=(const std::_Rb_tree_iterator<std::pair<const foo<int>,
std::vector<foo<int>, std::allocator<foo<int> > > >, std::pair<const
foo<int>, std::vector<foo<int>, std::allocator<foo<int> > > >&,
std::pair<const foo<int>, std::vector<foo<int>, std::allocator<foo<int> > >
>*>&)
What is it that i'm doing wrong?
Thanks in advance.
print_first is a const method. Therefore the member m_Map is also const, and its begin method doesn't return an ordinary iterator, but a const_iterator. Change
typename std::map<foo<T>,std::vector<foo<T> > >::iterator it;
to
typename std::map<foo<T>,std::vector<foo<T> > >::const_iterator it;
and you should be good to go.
How would I best implement these? I thought of something like this:
using namespace std;
shape_container
shape_container::clone_deep () const
{
shape_container* ptr = new shape_container();
copy( data.begin(), data.end(), (*ptr).begin() );
return *ptr;
}
shape_container
shape_container::clone_shallow () const
{
return *( new shape_container(*this) );
}
The member data is defined as follows:
std::map<std::string, shape*> data;
This doesn't work, unfortunately. Here's the compiler errors, I don't really understand them:
g++ -Wall -O2 -pedantic -I../../UnitTest++/src/ -I./libfglwin/include/ -I. -c shape_container.cpp -o shape_container.o
/usr/include/c++/4.2.1/bits/stl_pair.h: In member function ‘std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*>& std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*>::operator=(const std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*>&)’:
/usr/include/c++/4.2.1/bits/stl_pair.h:69: instantiated from ‘static _OI std::__copy<<anonymous>, <template-parameter-1-2> >::copy(_II, _II, _OI) [with _II = std::_Rb_tree_const_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*> >, _OI = std::_Rb_tree_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*> >, bool <anonymous> = false, <template-parameter-1-2> = std::bidirectional_iterator_tag]’
/usr/include/c++/4.2.1/bits/stl_algobase.h:315: instantiated from ‘_OI std::__copy_aux(_II, _II, _OI) [with _II = std::_Rb_tree_const_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*> >, _OI = std::_Rb_tree_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*> >]’
/usr/include/c++/4.2.1/bits/stl_algobase.h:340: instantiated from ‘static _OI std::__copy_normal<<anonymous>, <anonymous> >::__copy_n(_II, _II, _OI) [with _II = std::_Rb_tree_const_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*> >, _OI = std::_Rb_tree_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*> >, bool <anonymous> = false, bool <anonymous> = false]’
/usr/include/c++/4.2.1/bits/stl_algobase.h:401: instantiated from ‘_OutputIterator std::copy(_InputIterator, _InputIterator, _OutputIterator) [with _InputIterator = std::_Rb_tree_const_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*> >, _OutputIterator = std::_Rb_tree_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*> >]’
shape_container.cpp:70: instantiated from here
/usr/include/c++/4.2.1/bits/stl_pair.h:69: error: non-static const member ‘const std::basic_string<char, std::char_traits<char>, std::allocator<char> > std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*>::first’, can't use default assignment operator
/usr/include/c++/4.2.1/bits/stl_algobase.h: In static member function ‘static _OI std::__copy<<anonymous>, <template-parameter-1-2> >::copy(_II, _II, _OI) [with _II = std::_Rb_tree_const_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*> >, _OI = std::_Rb_tree_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*> >, bool <anonymous> = false, <template-parameter-1-2> = std::bidirectional_iterator_tag]’:
/usr/include/c++/4.2.1/bits/stl_algobase.h:268: note: synthesized method ‘std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*>& std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*>::operator=(const std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, shape*>&)’ first required here
Somehow this looks unnecessarily complicated to me. Is that
true and can I make it better?
BTW, I have clone() methods
in the classes I derived from shape. Perhaps I can use them
for the clone_deep method? Are they ok? They look something
like this:
class shape
{
public:
/* Many methods. */
virtual shape* clone () const = 0;
protected:
colorRGB color_;
std::string name_;
};
class triangle2d : public shape
{
public:
/* Many methods. */
triangle2d* clone() const;
private:
point3d a_, b_, c_;
};
triangle2d*
triangle2d::clone() const
{
return new triangle2d(*this);
}
Usually a clone function would return a pointer to a new instance. What you are returning is an object by value which is copy constructed from a dynamically allocated isntance that is then leaked.
If you want to return by value then you should not use new.
E.g.
shape_container shape_container::clone_shallow () const
{
return *this;
}
If the data member is just a std::map instance, then it will be copied as part of your shallow clone in any case so there is no need to do the std::copy in the deep clone case, it's not trying to do anything different.
If you wanted to do a std::copy of a map you would need to use a std::insert_iterator.
I think that it might be easier to do a clone of each shape after the fact, though.
e.g.
shape_container shape_container::clone_deep() const
{
shape_container ret(*this);
for (std::map<std::string, shape*>::iterator i = ret.data.begin(); i != ret.data.end(); ++i)
{
i->second = i->second->clone();
}
return ret;
}
First of all your example leaks memory because you new a shape_container in your methods but then it gets copied out through the return value. You should be returning pointers as with your shape example.
The compiler errors look to be related in some way to the copying since it's complaining it can't generate an assignment operator for you. Again, try using pointers and that issue should go away.
If you do deep copy of map then you have to a new create map with all element with deep copy.
Think about reference counting approach , it will be better approach.
One option is to wrap your shape type in a type that performs a deep
copy of the object:
class shape_deep_copy_wrapper {
// ...
public:
shape_deep_copy_wrapper (shape * shape)
: m_my_shape (shape)
{
}
shape_deep_copy_wrapper (shape_deep_copy_wrapper const & rhs)
: m_my_shape (rhs.m_my_shape.deep_copy ())
{
}
// ...
private:
shape * m_my_shape;
};
Then construct a map with this type:
typedef std :: map < shape_deep_copy_wrapper , ... > DeepCopy ;
typedef std :: map < shape* , ... > ShallowCopy ;