When creating my own allocator in c++11 I am implementing the following interfaces. This works with vector but when trying to use this with map I get errors on missing items. I thought this was all I need to implement for c++11 since it will use allocator_traits in the stl implementations. What am I missing here? Do I need to define more methods / data structures for an allocator for std::map? I am seeing the following errors when trying to compile currently (see below). Line 3 main.cpp is just
#include <map>
template <class T> struct MyAllocator {
typedef T value_type;
MyAllocator() noexcept; // only required if used
MyAllocator(const MyAllocator&) noexcept; // copies must be equal
MyAllocator(MyAllocator&&) noexcept; // not needed if copy ctor is good enough
template <class U> MyAllocator(const MyAllocator<U>& u) noexcept;
// requires: *this == MyAllocator(u)
value_type* allocate(std::size_t);
void deallocate(value_type*, std::size_t) noexcept;
};
template <class T, class U> bool
operator==(const MyAllocator<T>&, const MyAllocator<U>&) noexcept;
Errors:
In file included from
/opt/gcc-4.8.1/usr/local/include/c++/4.8.1/map:61:0,
from main.cpp:3:
/opt/gcc-4.8.1/usr/local/include/c++/4.8.1/bits/stl_map.h: In
instantiation of ‘class std::map,
MyAlloc >’:
main.cpp:146:14: required from here
/opt/gcc-4.8.1/usr/local/include/c++/4.8.1/bits/stl_map.h:143:58:
error: no type named ‘pointer’ in ‘std::map,
MyAlloc >::_Pair_alloc_type {aka class
MyAlloc, 200 typedef typename
_Pair_alloc_type::pointer pointer; ^
/opt/gcc-4.8.1/usr/local/include/c++/4.8.1/bits/stl_map.h:144:58:
error: no type named ‘const_pointer’ in ‘std::map, MyAlloc >::_Pair_alloc_type {aka class
MyAlloc
/opt/gcc-4.8.1/usr/local/include/c++/4.8.1/bits/stl_map.h:145:58:
error: no type named ‘reference’ in ‘std::map, MyAlloc >::_Pair_alloc_type {aka class
MyAlloc, 2 typedef typename
_Pair_alloc_type::reference reference; ^
/opt/gcc-4.8.1/usr/local/include/c++/4.8.1/bits/stl_map.h:146:58:
error: no type named ‘const_reference’ in ‘std::map, MyAlloc >::_Pair_alloc_type {aka class
MyAlloc
In file included from
/opt/gcc-4.8.1/usr/local/include/c++/4.8.1/map:60:0,
from main.cpp:3:
/opt/gcc-4.8.1/usr/local/include/c++/4.8.1/bits/stl_tree.h: In
instantiation of ‘void std::_Rb_tree<_Key, _Val, _KeyOfValue,
_Compare, _Alloc>::_M_destroy_node(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_t /opt/gcc-4.8.1/usr/local/include/c++/4.8.1/bits/stl_tree.h:1124:23:
required from ‘void std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare,
_Alloc>::_M_erase(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type /opt/gcc-4.8.1/usr/local/include/c++/4.8.1/bits/stl_tree.h:671:28:
required from ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare,
_Alloc>::~_Rb_tree() [with _Key = int; _Val = std::pair; _KeyOfValue = std::
/opt/gcc-4.8.1/usr/local/include/c++/4.8.1/bits/stl_map.h:96:11:
required from here
/opt/gcc-4.8.1/usr/local/include/c++/4.8.1/bits/stl_tree.h:421:2:
error: ‘std::_Rb_tree,
std::_Select1st >, std::less,
MyAlloc, 200ul> >:
_M_get_Node_allocator().destroy(__p); ^
make: *** [main.o] Error 1
The first errors are solved using some typedefs within MyAllocator:
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef const T* const_pointer;
Please post your new compilation output.
Basically as my comment suggested I needed to put the typedefs for the following and a construct and destroy
template <class U>
struct rebind {typedef MyAlloc<U, N> other;};
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
/// Call constructor with many arguments
template<typename U, typename... Args>
void construct(U* p, Args&&... args)
{
// Placement new
::new((void *)p) U(std::forward<Args>(args)...);
}
/// Call destructor
template<typename U>
void destroy(U* p)
{
p->~U();
}
Related
I have a C11 std::vector of structures. The structure contains an iterator to another structure of the same type, describing a tree.
Using a forward declaration doesn't work, because vector needs to have the full definition of the structure, but vector can't have the full definition of the structure until definition is complete.
#include <vector>
template <class Payload>
class Tree
{
public:
typedef struct _Node Node;
struct _Node
{
Payload t_payload;
//error: invalid use of incomplete type '_Value_type {aka struct _Node}'
std::vector<Node>::iterator pst_father;
};
std::vector<Node> gast_tree;
};
int main()
{
Tree<int> my_tree;
return 0;
}
in instantiation of 'void std::_Destroy(_ForwardIterator, _ForwardIterator) [with _ForwardIterator = _Node*]':
required from 'void std::_Destroy(_ForwardIterator, _ForwardIterator, std::allocator<_T2>&) [with _ForwardIterator = _Node*; _Tp = _Node]'
required from 'std::vector<_Tp, _Alloc>::~vector() [with _Tp = _Node; _Alloc = std::allocator<_Node>]'
required from here
error: invalid use of incomplete type '_Value_type {aka struct _Node}'
I want std::vector to serve as container for the Node structure, and I want Node(s) to link with each others to build a tree. It would be trivial using int indexes instead of iterators and resolving the reference later, but I'm trying to learn std::vector<>::iterators. This compiles just fine:
#include <vector>
template <class Payload>
class Tree
{
public:
typedef struct _Node
{
Payload t_payload;
//use a dumb index
int s32_father_index;
} Node;
std::vector<Node> gast_tree;
};
int main()
{
Tree<int> my_tree;
return 0;
}
I tried several ways, but I can't get the iterator to compile. Is it possible to have an iterator to an object inside the object?
SOLUTION
The keyword typedef is redundant in C++.
The keyword typename can be used in this scenario where the definition for the template is still incomplete. Details.
#include <vector>
template <class Payload>
class Tree
{
public:
struct Node
{
Payload t_payload;
typename std::vector<Node>::iterator pst_father;
};
std::vector<Node> gast_tree;
};
int main()
{
Tree<int> my_tree;
return 0;
}
SOLUTION
The keyword typedef is redundant in C++.
The keyword typename can be used in this scenario where the definition for the template is still incomplete.
#include <vector>
template <class Payload>
class Tree
{
public:
struct Node
{
Payload t_payload;
typename std::vector<Node>::iterator pst_father;
};
std::vector<Node> gast_tree;
};
int main()
{
Tree<int> my_tree;
return 0;
}
#ifndef _QUEUE_HPP
#define _QUEUE_HPP
#include <iostream>
#include "Node.hpp"
namespace std{
template<typename T>
class Queue{
public:
class Node<T>* front;
class Node<T>* rear;
Queue();
void enqueue(T data);
T dequeue();
~Queue();
template<class U>
friend std::ostream& operator<<(std::ostream& out,Queue<U> const& queue);
};
template<class classT>
std::ostream& operator<<(std::ostream& out,Queue<classT> const& queue);
template class Queue<double>;
template std::ostream& operator<<(std::ostream& out,Queue<double> const& queue);
}
#endif
Compile result
g++ -std=c++11 main.cpp Stack.o Queue.o -o test
In file included from main.cpp:2:0:
Queue.hpp: In instantiation of ‘std::ostream& std::operator<<(std::ostream&, const std::Queue<classT>&) [with classT = double; std::ostream = std::basic_ostream<char>]’:
Queue.hpp:25:81: required from here
Queue.hpp:25:81: error: explicit instantiation of ‘std::ostream& std::operator<<(std::ostream&, const std::Queue<classT>&) [with classT = double; std::ostream = std::basic_ostream<char>]’ but no definition available [-fpermissive]
mplate std::ostream& operator<<(std::ostream& out,Queue<double> const& queue);
Problem:
What happens with my code? I believe I have template operator<<being defined but the compiler can't find a definition.
I have the following piece of code -
#include <map>
using Type1 = std::map<std::string, unsigned long long>;
using Type2 = std::map<std::string, Type1>;
class T
{
private:
Type2 mymap;
public:
const Type1& get(const std::string& key) const;
};
const Type1& T::get(const std::string& key) const
{
return mymap[key];
}
int main(void)
{
}
This does not compile and the compiler complains -
maps.cpp: In member function ‘const Type1& T::get(const string&)
const’: maps.cpp:17:20: error: passing ‘const Type2 {aka const
std::map<std::basic_string<char>, std::map<std::basic_string<char>,
long long unsigned int> >}’ as ‘this’ argument of ‘std::map<_Key, _Tp,
_Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = std::basic_string<char>; _Tp = std::map<std::basic_string<char>, long
long unsigned int>; _Compare = std::less<std::basic_string<char> >;
_Alloc = std::allocator<std::pair<const std::basic_string<char>, std::map<std::basic_string<char>, long long unsigned int> > >;
std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type =
std::map<std::basic_string<char>, long long unsigned int>;
std::map<_Key, _Tp, _Compare, _Alloc>::key_type =
std::basic_string<char>]’ discards qualifiers [-fpermissive]
return mymap[key];
^
I need help understanding this error. From what I can tell I am not modifying "this" in the get function.
Thanks!
The errors comes from the fact that
std::map::operator[] can
inserts the key if the it does not exist.
You could do a std::map::find first as a check.
I'm trying to do the following (only relevant parts of code below):
template<typename ContainerType>
struct IsContainerCheck : is_container<ContainerType>
{
static constexpr char* err_value = "Type is not a container model";
};
namespace _check_concept {
template<typename ResultType>
struct run {
constexpr static int apply() {
static_assert(false, IsContainerCheck<ResultType>::err_value)
return 0;
}
};
template<>
struct run<true_t> {
constexpr static int apply() {
return 0;
}
};
}
This fails because the static_assert allows only literals to be printed. The same is with BOOST_STATIC_ASSERT_MSG macro.
So my question is - is there any way to output a constexpr string during compilation?
If there is a gcc extension providing this functionality that would also be great.
Used compiler gcc 4.8.1
GCC does not provide such a mechanism as you want. However you will not need
it if you are able to refactor your code somewhat as illustrated in the
following program. (I have filled in a few gaps so as to give us a
compilable example):
#include <type_traits>
#include <vector>
template<typename ContainerType>
struct is_container
{
static bool const value = false;
};
template<>
struct is_container<std::vector<int>>
{
static bool const value = true;
};
template<typename ContainerType>
struct IsContainerCheck // : is_container<ContainerType> <- Uneccessary
{
static_assert(is_container<ContainerType>::value,
"Type is not a container model");
};
namespace _check_concept {
template<typename ResultType>
struct run {
constexpr static int apply() {
return (IsContainerCheck<ResultType>(),0);
}
};
// No such specialization is necessary. Delete it.
// template<>
// struct run<true_t> {
// constexpr static int apply() {
// return 0;
// }
//};
}
using namespace _check_concept;
int main(int argc, char **argv)
{
auto verdict0 = run<std::vector<int>>::apply();
(void)verdict0;
// The following line will static_assert: "Type is not a container model"
auto verdict1 = run<float>::apply();
(void)verdict1;
return 0;
}
In your specialization _check_concept::struct run<true_t> I presume that
true_t is not an alias or equivalent of std::true_type, but rather
just a place-holder for some ResultType that is a container type. As
the test program shows, no such specialization is now necessary, because
IsContainerCheck<ResultType>() will static_assert, or not, depending
on ResultType, in the unspecialized run<ResultType>::apply().
I had some time (and a good liqueur to come along with it) to think more about the problem. This is what I came up with:
namespace _details {
struct PassedCheck {
constexpr static int printError () {
return 0; //no error concept check passed
}
};
template<template<typename> class ConceptCheck, typename ...ModelTypes>
struct check_concept_impl;
template<template<typename> class ConceptCheck, typename FirstType, typename ...ModelTypes>
struct check_concept_impl<ConceptCheck, FirstType, ModelTypes...> : mpl::eval_if< typename ConceptCheck<FirstType>::type,
check_concept_impl<ConceptCheck, ModelTypes...>,
mpl::identity<ConceptCheck<FirstType>>>
{ };
template<template<typename> class ConceptCheck, typename LastType>
struct check_concept_impl<ConceptCheck, LastType> : mpl::eval_if<typename ConceptCheck<LastType>::type,
mpl::identity<PassedCheck>,
mpl::identity<ConceptCheck<LastType>>>
{ };
}
template<template<typename> class ConceptCheck, typename ...ModelTypes>
struct check_concept {
private:
typedef typename _details::check_concept_impl<ConceptCheck, ModelTypes...>::type result_type;
public:
// the constexpr method assert produces shorter, fixed depth (2) error messages than a nesting assert in the trait solution
// the error message is not trahsed with the stack of variadic template recursion
constexpr static int apply() {
return result_type::printError();
}
};
template<typename ContainerType>
struct IsContainerCheck : is_container<ContainerType>
{
template<typename BoolType = false_t>
constexpr static int printError () {
static_assert(BoolType::value, "Type is not a container model");
return 0;
}
};
and the usage:
check_concept<IsContainerCheck, std::vector<int>, std::vector<int>, float, int>::apply();
The solution is probably not the most elegant one but I it keeps the assert message short:
In file included from ../main.cpp:4:0:
../constraint.check.hpp: In instantiation of ‘static constexpr int IsContainerCheck::printError() [with BoolType = std::integral_constant; ContainerType = float]’:
../constraint.check.hpp:61:34: required from ‘static constexpr int check_concept::apply() [with ConceptCheck = IsContainerCheck; ModelTypes = {std::vector >, std::vector >, float, int}]’
../main.cpp:25:83: required from here
../constraint.check.hpp:74:3: error: static assertion failed: Type is not a container model
static_assert(BoolType::value, "Type is not a container model");
The assert is issued in a constexpr method after the check_concept template specialization has been done. Embedding the static assert directly into the template class definition would drag the whole check_concept_impl recursion stack into the error message.
So changing the IsContainerCheck trait to something like (rest of the changes omitted for readibility):
template<typename ContainerType>
struct IsContainerCheck
{
static_assert(is_container<ContainerType>::type::value, "Type is not a container model");
};
would yield an error
../constraint.check.hpp: In instantiation of ‘struct IsContainerCheck’:
../constraint.check.hpp:36:9: required from ‘struct _details::check_concept_impl’
/usr/include/boost/mpl/eval_if.hpp:38:31: required from ‘struct boost::mpl::eval_if, _details::check_concept_impl, boost::mpl::identity > > >’
../constraint.check.hpp:36:9: required from ‘struct _details::check_concept_impl >, float, int>’
/usr/include/boost/mpl/eval_if.hpp:38:31: required from ‘struct boost::mpl::eval_if, _details::check_concept_impl >, float, int>, boost::mpl::identity > > >’
../constraint.check.hpp:36:9: required from ‘struct _details::check_concept_impl >, std::vector >, float, int>’
../constraint.check.hpp:53:84: required from ‘struct check_concept >, std::vector >, float, int>’
../main.cpp:25:81: required from here
../constraint.check.hpp:72:2: error: static assertion failed: Type is not a container model
static_assert(is_container::type::value, "Type is not a container model");
As you can see each recursive eval_if call is emended in the error description which is bad because it makes the error message dependent from the amount and type of template parameters.
I have very simple and stupid trouble:
std::map<b2Vec2, b2Body*> mTakePoints;
mTakePoints.insert(std::make_pair(point, body));
Compiler says:
In file included from /usr/include/c++/4.4/string:50,
from /usr/include/ClanLib-2.2/ClanLib/Display/../Core/Text/string_types.h:34,
from /usr/include/ClanLib-2.2/ClanLib/Display/display.h:35,
from /usr/include/ClanLib-2.2/ClanLib/display.h:40,
from /home/pfight/Themisto/include/World/Actions/Action.hpp:21,
from /home/pfight/Themisto/include/World/Actions/TakeAction.hpp:21,
from /home/pfight/Themisto/src/World/Actions/TakeAction.cpp:18:
/usr/include/c++/4.4/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = b2Vec2]’:
/usr/include/c++/4.4/bits/stl_tree.h:1170: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = b2Vec2, _Val = std::pair<const b2Vec2, b2Body*>, _KeyOfValue = std::_Select1st<std::pair<const b2Vec2, b2Body*> >, _Compare = std::less<b2Vec2>, _Alloc = std::allocator<std::pair<const b2Vec2, b2Body*> >]’
/usr/include/c++/4.4/bits/stl_map.h:500: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::insert(const std::pair<const _Key, _Tp>&) [with _Key = b2Vec2, _Tp = b2Body*, _Compare = std::less<b2Vec2>, _Alloc = std::allocator<std::pair<const b2Vec2, b2Body*> >]’
/home/pfight/Themisto/src/World/Actions/TakeAction.cpp:43: instantiated from here
/usr/include/c++/4.4/bits/stl_function.h:230: error: no match for ‘operator<’ in ‘__x < __y’
/usr/include/ClanLib-2.2/ClanLib/Display/../Core/Text/string_data16.h:383: note: candidates are: bool operator<(const CL_StringData16&, const wchar_t*)
/usr/include/ClanLib-2.2/ClanLib/Display/../Core/Text/string_data16.h:382: note: bool operator<(const wchar_t*, const CL_StringData16&)
/usr/include/ClanLib-2.2/ClanLib/Display/../Core/Text/string_data16.h:381: note: bool operator<(const CL_StringData16&, const CL_StringData16&)
/usr/include/ClanLib-2.2/ClanLib/Display/../Core/Text/string_data8.h:383: note: bool operator<(const CL_StringData8&, const char*)
/usr/include/ClanLib-2.2/ClanLib/Display/../Core/Text/string_data8.h:382: note: bool operator<(const char*, const CL_StringData8&)
/usr/include/ClanLib-2.2/ClanLib/Display/../Core/Text/string_data8.h:381: note: bool operator<(const CL_StringData8&, const CL_StringData8&)
TakeAction.cpp:43 it is row with insert call. For fun I tried next:
std::pair<b2Vec2, b2Body*> item(point, body);
mTakePoints.insert(item);
All the same.
I'm pretty confused, explain please, what is wrong?
Did you define the following operator:?
bool operator< (const b2Vec2&, const b2Vec2&)
std::map requires that the less-than operator be defined for keys, or that a less-than operator be provided as a template argument. In particular, std::map is implemented as a (sorted) binary tree, and needs operator< to figure out where to put new items.
For map, set and the like ordered containers must be told where to put new items. This is done by implementing the less-than operator:
bool operator< (const b2Vec2& first, const b2Vec2& second)
{
return first.some_attribute < second.some_attribute;
}
You can see in the compilation error that it was missing:
/usr/include/c++/4.4/bits/stl_function.h:230: error: no match for ‘operator<’ in ‘__x < __y’
The rest of the output tells you that the compiler tried to find a suitable operator and failed.