It was actually quite simple, the conversion constructor will be called if the container's constructor was given an allocator instance as argument. It is logical that the container's constructor has to know the allocator instance.
For example, if the container is not given any argument, the default constructor of the allocator will be used.
#include <memory>
#include <set>
#include <iostream>
#include <type_traits>
void *default_allocator;
template <typename T>
struct Allocator
{
using value_type = T;
using pointer = T *;
using size_type = size_t;
int state;
Allocator(int s) : state(s)
{
std::cout << "default with arg " << typeid(T).name() << std::endl;
std::cout << "state " << state << std::endl;
}
Allocator() : Allocator(*static_cast<Allocator *>(default_allocator)) // state(static_cast<Allocator *>(default_allocator)->state)
{
std::cout << "default without arg " << typeid(T).name() << std::endl;
std::cout << "state " << state << std::endl;
}
template <class U>
Allocator(const Allocator<U> &other)
{
state = other.state;
std::cout
<< "conversion " << typeid(T).name() << " from " << typeid(U).name() << std::endl;
std::cout << "state " << state << std::endl;
}
pointer allocate(size_type n)
{
std::allocator<T> a;
return a.allocate(n);
}
void deallocate(pointer p, size_type n)
{
std::allocator<T> a;
a.deallocate(p, n);
}
};
template <class T, class Compare = std::less<T>>
using set = std::set<T, Compare, Allocator<T>>;
int main()
{
std::cout << "new Allocator<int>(10)" << std::endl;
default_allocator = static_cast<void *>(new Allocator<int>(10));
std::cout << std::endl;
std::cout << "alloc(20)" << std::endl;
Allocator<int> alloc(20);
std::cout << std::endl;
std::cout << "set<int> s1;" << std::endl;
set<int> s1;
std::cout << std::endl;
std::cout << "set<int> s2(alloc);" << std::endl;
set<int> s2(alloc);
}
new Allocator<int>(10)
default with arg i
state 10
alloc(20)
default with arg i
state 20
set<int> s1;
default without arg NSt3__111__tree_nodeIiPvEE
state 10
set<int> s2(alloc);
conversion NSt3__111__tree_nodeIiPvEE from i
state 20
rebind_alloc
is a type. It doesn't "do" anything. – Uncourtlytemplate<class U> allocator( const allocator<U> & o )
is technically not a "copy constructor", it's just a normal conversion constructor, but that's pedantic. – Uncourtlyrebind_alloc
? – Uncourtlyrebind_alloc
"? The default valueAlloc<T, Args>
that mimics the container's allocator type is fine for me. So I don't have a type problem but I would like the conversion constructor (thanks for the remark, I edited my question) to be called by my container instead of the default constructor. – Pipsissewarebind_alloc
does. – Uncourtlystd::list<T, A>
allocates nodes of some internal typeNode<T>
using the allocatorstd::allocator_traits<A>::rebind_alloc<Node<T>>
that I can choose to (and will by default) beA<Node<T>, Args>
. Now the allocatorA<T>
I passed tolist
is stateful and I want the state to be transfered to the allocator of the internal type. – PipsissewaA<Node<T>, Args>
is called every time I declase alist<T, A>
. But I would like it to take the container's instance ofA<T>
as argument (or any other way that would allow me to share a state). – Pipsissewastd::list
constructor? Can you show code that has the problem? – Uncourtly