6

Take the following code snippet:

#include <vector>

std::vector<int> good;

//illegal, because std::allocator<const T> is ill-formed
std::vector<const int> bad;

//fails to compile under MSVS 2017
std::vector<const int, my_custom_allocator> X;

Why does X fail to compile? MSVS 2017 shows

Error C2338 (failed static assert): The C++ Standard forbids containers of const elements because allocator is ill-formed.

It is my understanding that this is not necessarily correct.

According to 20.5.3.5 [allocator.requirements] (and many SO questions), an allocator of a const T is ill-formed - but as I understand it, it is also possible to define an allocator that only works with a single type (meaning, a non-templated allocator). This avoids, albeit in a slightly pedantic way, the language restriction. It is also my understanding that since templates are instantiated at compile time, the default value for the vector's allocator (i.e., std::allocator<const T>) is never instantiated - and that, therefore, the last line does not break that rule.

Ignoring the use cases and alternatives (and the fact that const std::vector<int> probably solves your problem), and given a valid my_custom_allocator: is std::vector<const int, my_custom_allocator> really ill-formed?

osuka_
  • 484
  • 5
  • 15
  • 4
    I believe that makes `my_custom_allocator` not an allocator instead. – Passer By Mar 22 '19 at 19:09
  • An allocator that works for one type, but which one? The one the container needs? – curiousguy Mar 25 '19 at 17:37
  • @curiousguy yes, since otherwise the behavior is undefined. – osuka_ Mar 25 '19 at 17:38
  • @osuka_ How can you know in advance which type of objects the container wants to allocate? – curiousguy Mar 25 '19 at 17:46
  • @curiousguy you’ll know because you’ll have implemented it. Regardless of that, however, the question is not about the allocator itself - but rather about the legality of a container type such as the one discussed above. – osuka_ Mar 25 '19 at 17:48

1 Answers1

5

I think it would still be ill-formed. According to [allocator.requirements], an allocator is supposed to work with objects of a type T which is defined to be

any cv-unqualified object type

Based on that, it would seem to me that anything that works with const T cannot satisfy the requirements to be an allocator and, thus, cannot be used as an allocator for a standard container…

Michael Kenzel
  • 15,508
  • 2
  • 30
  • 39
  • But what about a theoretical `custom_const_allocator`, which would have cv-unqualified `T` - but would have `Allocator::value_type = const T`? – osuka_ Mar 22 '19 at 19:21
  • 3
    [allocator.requirements] requires that the `value_type` of an allocator be a *cv*-unqualified object type. Thus, this would not be legal… – Michael Kenzel Mar 22 '19 at 19:23
  • Ah, you seem to be correct. There are no requirements imposed on `value_type` itself, but since it must be *identical* to `T`, it would seem that it would be illegal. – osuka_ Mar 22 '19 at 19:28
  • Well, the fact that `value_type` must be identical to `T` (where `T` is the type the allocator is an allocator for) is what I would call a requirement imposed on `value_type`… ;-) – Michael Kenzel Mar 22 '19 at 19:30
  • You've just proved to me that I can write neither C++, nor English. What a day! – osuka_ Mar 22 '19 at 19:31