C++ Custom class inhereting Eigen initializer list - c++

I am trying to make a custom Vector3 inheriting from Eigen's vector 3 like so.
using Vector3 = Eigen::Vector3d;
enum class CustomEnum
{
E1, E2 E3, E4,
};
class CustomVector3 : public Vector3
{
public:
// Taken from here: https://eigen.tuxfamily.org/dox/TopicCustomizing_InheritingMatrix.html
CustomVector3():Vector3(){}
template<typename OtherDerived>
CustomVector3(const Eigen::MatrixBase<OtherDerived>& other) : Vector3(other) {}
// Initializer Constructor
template<typename OtherDerived>
CustomVector3(const std::initializer_list<OtherDerived>& other) : Vector3(other) {}
template<typename OtherDerived>
CustomVector3& operator=(const Eigen::MatrixBase<OtherDerived>& other){
this->Vector3::operator=(other);
return *this;
}
CustomEnum e = CustomEnum::E1;
};
And the goal is to do the following:
TEST_CASE("Initalizer List Test")
{
CustomVector3 vec = {1.1, 2.2, 3.3};
CHECK(vec.x() == 1.1);
CHECK(vec.y() == 2.2);
CHECK(vec.z() == 3.3);
assert(vec.frame == CustomEnum::E1);
}
Without the initializer constructor, I am able to do the following, but not my goal mentioned above:
Vector3 data = {1.1, 2.2, 3.3};
CustomVector3 framedData = data;
With the initializer constructor, I get the following compile error message (I called it FramedVector3 in my code, but for clarity I called it CustomVector3 in this post):
/usr/include/eigen3/Eigen/src/Core/Matrix.h: In instantiation of ‘Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::Matrix(const T&) [with T = std::initializer_list<double>; _Scalar = double; int _Rows = 3; int _Cols = 1; int _Options = 0; int _MaxRows = 3; int _MaxCols = 1]’:
/home/seedship/uavAP/include/uavAP/Core/FramedVector3.h:23:81: required from ‘FramedVector3::FramedVector3(const std::initializer_list<_Tp>&) [with OtherDerived = double]’
/home/seedship/uavAP/include/uavAP/Core/SensorData.h:128:38: required from here
/usr/include/eigen3/Eigen/src/Core/Matrix.h:294:31: error: no matching function for call to ‘Eigen::Matrix<double, 3, 1>::_init1<std::initializer_list<double> >(const std::initializer_list<double>&)’
294 | Base::template _init1<T>(x);
| ~~~~~~~~~~~~~~~~~~~~~~~~^~~
In file included from /usr/include/eigen3/Eigen/Core:462,
from /usr/include/eigen3/Eigen/Dense:1,
from /usr/local/include/cpsCore/Utilities/LinearAlgebra.h:13,
from /home/seedship/uavAP/include/uavAP/Core/FramedVector3.h:9,
from /home/seedship/uavAP/include/uavAP/Core/SensorData.h:11,
from /home/seedship/uavAP/include/uavAP/Core/Orientation/ENU.h:8,
from /home/seedship/uavAP/src/Core/Orientation/ENU.cpp:5:
/usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h:774:30: note: candidate: ‘void Eigen::PlainObjectBase<Derived>::_init1(Eigen::Index, typename Eigen::internal::enable_if<(((typename Eigen::internal::dense_xpr_base<Derived>::type::SizeAtCompileTime != 1) || (! Eigen::internal::is_convertible<T, typename Eigen::internal::traits<T>::Scalar>::value)) && ((! Eigen::internal::is_same<typename Eigen::internal::traits<T>::XprKind, Eigen::ArrayXpr>::value) || (typename Eigen::internal::dense_xpr_base<Derived>::type::SizeAtCompileTime == Eigen::Dynamic))), T>::type*) [with T = std::initializer_list<double>; Derived = Eigen::Matrix<double, 3, 1>; Eigen::Index = long int; typename Eigen::internal::enable_if<(((typename Eigen::internal::dense_xpr_base<Derived>::type::SizeAtCompileTime != 1) || (! Eigen::internal::is_convertible<T, typename Eigen::internal::traits<T>::Scalar>::value)) && ((! Eigen::internal::is_same<typename Eigen::internal::traits<T>::XprKind, Eigen::ArrayXpr>::value) || (typename Eigen::internal::dense_xpr_base<Derived>::type::SizeAtCompileTime == Eigen::Dynamic))), T>::type = std::initializer_list<double>]’
774 | EIGEN_STRONG_INLINE void _init1(Index size, typename internal::enable_if< (Base::SizeAtCompileTime!=1 || !internal::is_convertible<T, Scalar>::value)
| ^~~~~~
/usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h:774:43: note: no known conversion for argument 1 from ‘const std::initializer_list<double>’ to ‘Eigen::Index’ {aka ‘long int’}
774 | EIGEN_STRONG_INLINE void _init1(Index size, typename internal::enable_if< (Base::SizeAtCompileTime!=1 || !internal::is_convertible<T, Scalar>::value)
| ~~~~~~^~~~
/usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h:788:30: note: candidate: ‘template<class T> void Eigen::PlainObjectBase<Derived>::_init1(const Scalar&, typename Eigen::internal::enable_if<((typename Eigen::internal::dense_xpr_base<Derived>::type::SizeAtCompileTime == 1) && Eigen::internal::is_convertible<T, typename Eigen::internal::traits<T>::Scalar>::value), T>::type*) [with T = T; Derived = Eigen::Matrix<double, 3, 1>]’
788 | EIGEN_STRONG_INLINE void _init1(const Scalar& val0, typename internal::enable_if<Base::SizeAtCompileTime==1 && internal::is_convertible<T, Scalar>::value,T>::type* = 0)
| ^~~~~~
/usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h:788:30: note: template argument deduction/substitution failed:
/usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h: In substitution of ‘template<class T> void Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1> >::_init1<T>(const Scalar&, typename Eigen::internal::enable_if<((Eigen::MatrixBase<Eigen::Matrix<double, 3, 1> >::SizeAtCompileTime == 1) && Eigen::internal::is_convertible<T, double>::value), T>::type*) [with T = std::initializer_list<double>]’:
/usr/include/eigen3/Eigen/src/Core/Matrix.h:294:31: required from ‘Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::Matrix(const T&) [with T = std::initializer_list<double>; _Scalar = double; int _Rows = 3; int _Cols = 1; int _Options = 0; int _MaxRows = 3; int _MaxCols = 1]’
/home/seedship/uavAP/include/uavAP/Core/FramedVector3.h:23:81: required from ‘FramedVector3::FramedVector3(const std::initializer_list<_Tp>&) [with OtherDerived = double]’
/home/seedship/uavAP/include/uavAP/Core/SensorData.h:128:38: required from here
/usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h:788:30: error: invalid use of incomplete type ‘struct Eigen::internal::enable_if<false, std::initializer_list<double> >’
[Truncated for brevity]
Can anyone explain what I am missing? I'm confused why the assignment operator works, but not the constructor. This happens on both Eigen 3.3.9-1 and eigen-git.
Update: maybe this question is very library specific, so I asked on the Eigen gitlab project (https://gitlab.com/libeigen/eigen/-/issues/2192)

You need to use an extra pair of parenthesis. Also there is no point in templating this constructor since the template argument type needs to match the scalar type of the Eigen vector and if you'd like the scalar type to be configurable you'd need to template the whole class.
In summary
CustomVector3(const std::initializer_list<double>& other) : Vector3({other}) {}
is the correct way to do this. The reason is that Eigen::Vector3d is a typedef for Eigen::Matrix<double, 3, 1>. The initializer list constructor for matrices needs to handle multiple rows and columns however and has thus the signature
explicit PlainObjectBase(const std::initializer_list<std::initializer_list<Scalar>>& list);
If you always want to use 3D vectors the (easier) alternative is to use Eigen's 3D constructor and aggregate initialization:
CustomVector3(double x, double y, double z) : Vector3(x, y, z) {}

Related

c++ eigen static assert confuses enum with float

Here is the code:
#include <Eigen/Dense>
using namespace Eigen;
enum { TWO = 2};
Matrix<float, Dynamic, TWO> m1(42, 2); // good...
Matrix<float, Dynamic, TWO> m2(42, int(TWO)); // good...
Matrix<float, Dynamic, TWO> m3(42, TWO); // error!
When I compile the declaration of m3 is raising an error as if the enum value TWO is a floating point number:
$ g++ -I/usr/include/eigen3 -c bug.cpp
In file included from /usr/include/eigen3/Eigen/Core:366,
from /usr/include/eigen3/Eigen/Dense:1,
from bug.cpp:1:
/usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h: In instantiation of ‘void Eigen::PlainObjectBase<Derived>::_init2(Eigen::Index, Eigen::Index, typename Eigen::internal::enable_if<(typename Eigen::internal::dense_xpr_base<Derived>::type::SizeAtCompileTime != 2), T0>::type*) [with T0 = int; T1 = <unnamed enum>; Derived = Eigen::Matrix<float, -1, 2>; Eigen::Index = long int; typename Eigen::internal::enable_if<(typename Eigen::internal::dense_xpr_base<Derived>::type::SizeAtCompileTime != 2), T0>::type = int]’:
/usr/include/eigen3/Eigen/src/Core/Matrix.h:302:35: required from ‘Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::Matrix(const T0&, const T1&) [with T0 = int; T1 = <unnamed enum>; _Scalar = float; int _Rows = -1; int _Cols = 2; int _Options = 0; int _MaxRows = -1; int _MaxCols = 2]’
bug.cpp:6:39: required from here
/usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h:740:58: error: static assertion failed: FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED
740 | EIGEN_STATIC_ASSERT(bool(NumTraits<T0>::IsInteger) &&
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
741 | bool(NumTraits<T1>::IsInteger),
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/eigen3/Eigen/src/Core/util/StaticAssert.h:33:54: note: in definition of macro ‘EIGEN_STATIC_ASSERT’
33 | #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG);
|
The error message is just not chosen well since it always mentions floating points as causing the issue, but the point is that you need to pass an integer type, which an enumeration type is not.
However, with Eigen version 3.3.8 this has been changed and an enumeration type is now accepted as well and will be converted to its underlying integer type, see this issue resulting in this commit. Since that version your code compiles fine, see https://godbolt.org/z/W4jYbKfns.

C++ concept: check if a method/operator exists no matter what return type is

Suppose I am writing a template function that wants to call operator+= on its template parameter and does not care whether it returns the new value (of type T), a void, or whatever else. For example:
template<class T>
void incrementAll(T *array, int size, T value) {
for (int i = 0; i < size; ++i) {
array[i] += value;
}
}
I want to have a constraint on this function: to make it require a concept on T. However, I couldn't find one that does not have any requirement on the return type. The only idea I could come up with was std::convertible_to<void> (because we can convert any value to void, right?), but it fails:
#include <concepts>
template<class T>
concept Incrementable = requires(T a, T b) {
{a += b} -> std::convertible_to<void>;
};
template<class T> requires Incrementable<T>
void incrementAll(T *array, int size, T value) {
for (int i = 0; i < size; ++i) {
array[i] += value;
}
}
int main() {
int arr[] = {1};
incrementAll(arr, 1, 1);
}
nikolay#KoLin:~$ g++ another_tmp.cpp -std=c++20 -fconcepts-diagnostics-depth=10
another_tmp.cpp: In function ‘int main()’:
another_tmp.cpp:17:21: error: no matching function for call to ‘incrementAll(int [1], int, int)’
17 | incrementAll(arr, 1, 1);
| ~~~~~~~~~~~~^~~~~~~~~~~
another_tmp.cpp:9:6: note: candidate: ‘template<class T> requires Incrementable<T> void incrementAll(T*, int, T)’
9 | void incrementAll(T *array, int size, T value) {
| ^~~~~~~~~~~~
another_tmp.cpp:9:6: note: template argument deduction/substitution failed:
another_tmp.cpp:9:6: note: constraints not satisfied
another_tmp.cpp: In substitution of ‘template<class T> requires Incrementable<T> void incrementAll(T*, int, T) [with T = int]’:
another_tmp.cpp:17:14: required from here
another_tmp.cpp:4:9: required for the satisfaction of ‘Incrementable<T>’ [with T = int]
another_tmp.cpp:4:25: in requirements with ‘T a’, ‘T b’ [with T = int]
another_tmp.cpp:5:12: note: ‘a += b’ does not satisfy return-type-requirement, because
5 | {a += b} -> std::convertible_to<void>;
| ~~^~~~
another_tmp.cpp:5:10: error: deduced expression type does not satisfy placeholder constraints
5 | {a += b} -> std::convertible_to<void>;
| ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
another_tmp.cpp:5:10: note: constraints not satisfied
In file included from another_tmp.cpp:1:
/usr/include/c++/11.2.0/concepts:72:13: required for the satisfaction of ‘convertible_to<decltype(auto) [requires std::convertible_to<<placeholder>, void>], void>’ [with decltype(auto) [requires std::convertible_to<<placeholder>, void>] = int&]
/usr/include/c++/11.2.0/concepts:72:30: note: the expression ‘is_convertible_v<_From, _To> [with _From = int&; _To = void]’ evaluated to ‘false’
72 | concept convertible_to = is_convertible_v<_From, _To>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
So, what is the correct concept to define here?
If you don't care what its return type is, then you can simply use the requires-clause to require the expression a += b to be well-formed:
template<class T>
concept Incrementable = requires(T a, T b) {
a += b;
};
However, such a concept seems too loose for the incrementable type, and it seems more appropriate to require the return type to be T& like {a += b} -> same_as<T&> and name it AdditionAssignable or something.

user-defined conversion cannot use static_cast in C++

I am trying to solve some problems with Eigen. In the process, I found that static_cast and user-defined conversion conflict, maybe the problem caused by std::enable_if?
Here is basically what I tried:
#include <Eigen/Dense>
#include <bits/stdc++.h>
using namespace std;
class Vector2
{
public:
operator Eigen::Vector2d ()
{
return data;
}
private:
Eigen::Vector2d data;
};
class Box2
{
public:
void Extend(const Vector2 & a)
{
data.extend( static_cast<Eigen::Vector2d>(a) ); // error, but why?
}
private:
Eigen::AlignedBox2d data;
};
int main()
{
Vector2 a;
Eigen::Vector2d b = a; // ok, implicit conversion
return 0;
}
g++ -std=c++11outputs a lot of error logs, this is the last part:
eigen/eigen/Eigen/src/Core/PlainObjectBase.h:863:30: note: template argument deduction/substitution failed:
eigen/eigen/Eigen/src/Core/PlainObjectBase.h: In substitution of ‘template<class T> void Eigen::PlainObjectBase<Derived>::_init1(const Index&, typename Eigen::internal::enable_if<((((((! Eigen::internal::is_same<long int, typename Eigen::internal::traits<T>::Scalar>::value) && Eigen::internal::is_same<long int, T>::value) && (typename Eigen::internal::dense_xpr_base<Derived>::type:: SizeAtCompileTime != Eigen::Dynamic)) && (typename Eigen::internal::dense_xpr_base<Derived>::type:: SizeAtCompileTime != 1)) && Eigen::internal::is_convertible<T, typename Eigen::internal::traits<T>::Scalar>::value) && Eigen::internal::is_same<typename Eigen::internal::traits<T>::XprKind, Eigen::ArrayXpr>::value), T*>::type*) [with T = T; Derived = Eigen::Matrix<double, 2, 1>] [with T = Vector2]’:
eigen/eigen/Eigen/src/Core/Matrix.h:296:33: required from ‘Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::Matrix(const T&) [with T = Vector2; _Scalar = double; int _Rows = 2; int _Cols = 1; int _Options = 0; int _MaxRows = 2; int _MaxCols = 1]’
test.cpp:21:52: required from here
eigen/eigen/Eigen/src/Core/PlainObjectBase.h:863:30: error: invalid use of incomplete type ‘struct Eigen::internal::enable_if<false, Vector2*>’
In file included from eigen/eigen/Eigen/Core:364:0,
from eigen/eigen/Eigen/Dense:1,
from eigen/eigen/Eigen/Eigen:1,
from test.cpp:2:
eigen/eigen/Eigen/src/Core/util/Meta.h:162:50: error: declaration of ‘struct Eigen::internal::enable_if<false, Vector2*>’
template<bool Condition, typename T=void> struct enable_if;
^
It seems like the issue of enable_if, I wonder why static_cast doesn't work. Is there a way to solve this problem without modifying Eigen? It is ok to do this now:
void Extend(Vector2 a)
{
Eigen::Vector2d b = a;
data.extend( b );
}
But it's too ugly.
It seems like the issue of enable_if, I wonder why static_cast doesn't
work.
This has nothing to do with the static_cast itself. The error is generated because Vector2's operator Eigen::Vector2d () isn't defined for const objects and since your Box2::Extend() takes a const Vector2& a, the appropriate casting isn't defined for that line in the code. Add a const version of Vector2's user defined casting to Eigen::Vector2d to make it both compile and keep the const-correctness of the code:
const operator Eigen::Vector2d () const
{
return data;
}
Now the usage is working like you wanted:
int main()
{
Vector2 a;
Eigen::Vector2d b = a; // ok, implicit conversion
Box2 boxy;
boxy.Extend(a); // also ok, implicit conversion inside, from a const&
return 0;
}

Use of funcName() before deduction of auto — why in one case but not the other?

Consider the following code:
#include <unordered_map>
#include <tuple>
namespace Test
{
template<typename State>
struct StateTableEntry
{
State state;
};
template<typename State>
using StateRow = std::unordered_map<int,StateTableEntry<State>>;
template<typename StateRowValueType>
auto& entryBAD(StateRowValueType& row)
{ return row.second; }
template<typename StateRowValueType>
auto entryOK(StateRowValueType& row) -> decltype((row.second))
{ return row.second; }
}
template<class T,int I,class O> std::enable_if_t<I==std::tuple_size<T>::value>
for_each_index_of(O&){}
template<class Tuple, int startingIndex=0, class Operation>
std::enable_if_t<startingIndex<std::tuple_size<Tuple>::value>
for_each_index_of(const Operation& operation)
{
operation(std::integral_constant<std::size_t,startingIndex>());
for_each_index_of<Tuple,startingIndex+1>(operation);
}
int main()
{
for_each_index_of<std::tuple<int>>([](const auto&)
{
Test::StateRow<long> stateRow;
for(auto& rowElement : stateRow)
{
auto& state(entryBAD(rowElement).state);
state=1;
}
});
}
If I try to compile it as is, gcc tells me
test.cpp: In instantiation of ‘main()::<lambda(const auto:1&)> [with auto:1 = std::integral_constant<long unsigned int, 0ul>]’:
test.cpp:29:14: required from ‘std::enable_if_t<(startingIndex < std::tuple_size<_Tp>::value)> for_each_index_of(const Operation&) [with Tuple = std::tuple<int>; int startingIndex = 0; Operation = main()::<lambda(const auto:1&)>; std::enable_if_t<(startingIndex < std::tuple_size<_Tp>::value)> = void]’
test.cpp:43:6: required from here
test.cpp:40:44: error: use of ‘template<class StateRowValueType> auto& Test::entryBAD(StateRowValueType&)’ before deduction of ‘auto’
auto& state(entryBAD(rowElement).state);
^
test.cpp:40:44: error: use of ‘auto& Test::entryBAD(StateRowValueType&) [with StateRowValueType = std::pair<const int, Test::StateTableEntry<long int> >]’ before deduction of ‘auto’
test.cpp:24:1: error: ‘std::enable_if_t<(I == std::tuple_size<_Tp>::value)> for_each_index_of(O&) [with T = std::tuple<int>; int I = 1; O = const main()::<lambda(const auto:1&)>; std::enable_if_t<(I == std::tuple_size<_Tp>::value)> = void]’, declared using local type ‘const main()::<lambda(const auto:1&)>’, is used but never defined [-fpermissive]
for_each_index_of(O&){}
^
But if I move the conde of lambda out of the lambda or replace call of entryBAD with entryOK, for some reason compilation succeeds. Same success if I move definition of entryBAD out of namespace Test.
Also, clang++ 3.6 compiles in all cases without complaints.
Is gcc right or is it a bug in it? If gcc is right, then what's wrong with the code?

Custom allocator works with vector but not with deque (wrapped within a queue)

I have written a custom allocator that allocates memory in a shared memory segment.
This line of code compiles (and runs) fine:
shp_arr = new (vecmem) vector<shape *,smallocator <shape*> > ;
But this line of code:
shp_queue = new (queuemem) queue< shape *, deque < shape *, smallocator< shape * > > > ;
gives me a number of errors. Here they are:
/usr/local/lib/gcc/i686-pc-cygwin/4.7.3/../../../../include/c++/4.7.3/bits/stl_deque.h: In
instantiation of ‘std::_Deque_base<_Tp, _Alloc>::_Map_alloc_type std::_Deque_base<_Tp,
_Alloc>::_M_get_map_allocator() const [with _Tp = shape*; _Alloc = smallocator<shape*>;
std::_Deque_base<_Tp, _Alloc>::_Map_alloc_type = smallocator<shape**>]’:
/usr/local/lib/gcc/i686-pc-cygwin/4.7.3/../../../../include/c++/4.7.3/bits/stl_deque.h:549:9:
required from ‘void std::_Deque_base<_Tp, _Alloc>::_M_deallocate_map(_Tp**, std::size_t) [with _Tp =
shape*; _Alloc = smallocator<shape*>; std::size_t = unsigned int]’
/usr/local/lib/gcc/i686-pc-cygwin/4.7.3/../../../../include/c++/4.7.3/bits/stl_deque.h:568:4:
required from ‘std::_Deque_base<_Tp, _Alloc>::~_Deque_base() [with _Tp = shape*; _Alloc =
smallocator<shape*>]’
/usr/local/lib/gcc/i686-pc-cygwin/4.7.3/../../../../include/c++/4.7.3/bits/stl_deque.h:781:15:
required from ‘std::deque<_Tp, _Alloc>::deque() [with _Tp = shape*; _Alloc = smallocator<shape*>]’
file.cpp:233:30: required from here
/usr/local/lib/gcc/i686-pc-cygwin/4.7.3/../../../../include/c++/4.7.3/bits/stl_deque.h:529:53: error:
no matching function for call to ‘smallocator<shape**>::smallocator(const _Tp_alloc_type&)’
/usr/local/lib/gcc/i686-pc-cygwin/4.7.3/../../../../include/c++/4.7.3/bits/stl_deque.h:529:53: note:
candidates are:
In file included from file.cpp:20:0:
smallocator.hpp:41:3: note: smallocator<T>::smallocator(const smallocator<T>&) [with T = shape**;
smallocator<T> = smallocator<shape**>]
smallocator.hpp:41:3: note: no known conversion for argument 1 from ‘const _Tp_alloc_type {aka const
smallocator<shape*>}’ to ‘const smallocator<shape**>&’
smallocator.hpp:40:3: note: smallocator<T>::smallocator() [with T = shape**]
smallocator.hpp:40:3: note: candidate expects 0 arguments, 1 provided
The interface to smallocator looks like this:
template <typename T>
class smallocator: public std::allocator<T>
{
public:
typedef size_t size_type;
typedef T* pointer;
typedef const T* const_pointer;
template<typename _Tp1>
struct rebind
{
typedef smallocator<_Tp1> other;
};
pointer allocate(size_type n, const void *hint=0)
{
...
}
void deallocate(pointer p, size_type n)
{
...
}
smallocator() throw(): std::allocator<T>() { std::cout <<"Hello allocator" <<std::endl;}
smallocator(const smallocator &a) throw(): std::allocator<T>(a) { }
~smallocator() throw() { }
};
Does anyone know what the problem is? Thanks!
You did not provide the following constructor for your smallocator :
template <class U>
smallocator(const smallocator<U>& a) throw();
You need all three :
smallocator() throw();
smallocator(const smallocator& a) throw();
template <class U>
smallocator(const smallocator<U>& a) throw();