Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does GCC think that the template parameter is int whereas it's a completely different type?

Tags:

c++

gcc

templates

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.

like image 739
rubix_addict Avatar asked Feb 25 '18 21:02

rubix_addict


1 Answers

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.

like image 125
T.C. Avatar answered Oct 12 '22 11:10

T.C.