I have a problem with compiling the following program using GCC (I've tried numerous versions, all fail with the same error). It compiles fine in Clang:
#include <vector>
struct Tag1
{
static void logAllocation(){}
static void logDeallocation(){}
};
struct Tag2
{
static void logAllocation(){}
static void logDeallocation(){}
};
template<typename Tag, typename T>
struct MyAllocator
{
using value_type = typename std::allocator<T>::value_type;
T* allocate(std::size_t n)
{
Tag::logAllocation();
return std::allocator<T>{}.allocate(n);
}
void deallocate(T* p, std::size_t n)
{
Tag::logDeallocation();
std::allocator<T>{}.deallocate(p, n);
}
};
int main()
{
std::vector<int, MyAllocator<Tag1, int>> vec;
}
The problem is that GCC thinks that Tag==int
inside MyAllocator
and I get an error that 'logDeallocation' is not a member of 'int'. Is this a bug in GCC? When I flip template parameters (template<typename T, typename Tag
) and declare my vector as std::vector<int, MyAllocator<int, Tag1>> vec;
it compiles.
This is not a conforming allocator, and supplying it as one to a library component results in undefined behavior (thus, both implementations are conforming). You are missing !=
, ==
, cross-type implicit conversion, and, as pertinent here, rebind
.
allocator_traits
's default rebind
implementation assumes that the value type is the first template parameter (and that any remaining template parameters can be reused unmodified). Since it's not the case for your allocator, you need to either supply your own rebind
or invert the template parameter order.
vector
is pretty special in that the implementation can, if it wants to, simply use the supplied allocator as-is without rebinding. That's why your example code compiles with libc++. libstdc++'s containers support an extension that allows you to do vector<int, allocator<char>>
, so it always rebinds the allocator to the specified value_type
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With