Container requirements are all stated in terms of CopyInsertable into X, and Erasable from X, which involves indirection through the container's allocator. The following test shows a class which can only be constructed/destroyed by its allocator, revealing that std::vector tries to construct temporaries directly without going through the allocator. /usr/local/libcxx-head/include/c++/v1/vector:1815:24: error: call to deleted constructor of 'value_type' (aka 'X') #include <vector> struct Tag { }; template<typename T> class TaggingAllocator { public: using value_type = T; TaggingAllocator() = default; template<typename U> TaggingAllocator(const TaggingAllocator<U>&) { } T* allocate(std::size_t n) { return std::allocator<T>{}.allocate(n); } void deallocate(T* p, std::size_t n) { std::allocator<T>{}.deallocate(p, n); } template<typename U, typename... Args> void construct(U* p, Args&&... args) { ::new((void*)p) U(Tag{}, std::forward<Args>(args)...); } template<typename U, typename... Args> void destroy(U* p) { p->~U(); } }; template<typename T, typename U> bool operator==(const TaggingAllocator<T>&, const TaggingAllocator<U>&) { return true; } template<typename T, typename U> bool operator!=(const TaggingAllocator<T>&, const TaggingAllocator<U>&) { return false; } struct X { // All constructors must be passed the Tag type. // DefaultInsertable into vector<X, TaggingAllocator<X>>, X(Tag) { } // CopyInsertable into vector<X, TaggingAllocator<X>>, X(Tag, const X&) { } // MoveInsertable into vector<X, TaggingAllocator<X>>, and X(Tag, X&&) { } // EmplaceConstructible into vector<X, TaggingAllocator<X>> from args. template<typename... Args> X(Tag, Args&&...) { } // not DefaultConstructible, CopyConstructible or MoveConstructible. X() = delete; X(const X&) = delete; X(X&&) = delete; // CopyAssignable. X& operator=(const X&) { return *this; } // MoveAssignable. X& operator=(X&&) { return *this; } private: // Not Destructible. ~X() { } // Erasable from vector<X, TaggingAllocator<X>>. friend class TaggingAllocator<X>; }; int main() { std::vector<X, TaggingAllocator<X>> v; v.reserve(3); v.emplace_back(); v.emplace(v.begin()); v.emplace(v.begin(), 1, 2, 3); } // template class std::vector<X, TaggingAllocator<X>>; Uncommenting the last line to explicitly instantiate the vector fails differently, presumably there are some SFINAE conditions which make invalid assumptions about the type.
revision 275105 fixes this for deque and vector. Leaving this open because I need to check the other containers.
> // template class std::vector<X, TaggingAllocator<X>>; > Uncommenting the last line to explicitly instantiate the vector fails differently, presumably there are some SFINAE conditions which make invalid assumptions about the type. The code that makes this blow up is in the SFINAE for assign: X *p = new X(Tag()); v.assign(p, p + 1); And this fails because is_constructible<X, X&>::value is false.
This was fixed in revision 275105 (back on Jul 11 2016)