-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Description
The following code snippet, which utilizes vector<bool>
with a custom-sized allocator with size_type = std::uint16_t
and difference_type = std::int16_t
, fails to compile due to an ambiguous call to std::max
within vector<bool>
:
#include <exception>
#include <iostream>
#include <limits>
#include <memory>
#include <vector>
template <typename T, typename SIZE_TYPE = std::size_t, typename DIFF_TYPE = std::ptrdiff_t>
class CustomSizedAllocator {
template <typename U, typename Sz, typename Diff>
friend class CustomSizedAllocator;
public:
using value_type = T;
using size_type = SIZE_TYPE;
using difference_type = DIFF_TYPE;
using propagate_on_container_swap = std::true_type;
explicit CustomSizedAllocator(int i = 0) : data_(i) {}
template <typename U, typename Sz, typename Diff>
constexpr CustomSizedAllocator(const CustomSizedAllocator<U, Sz, Diff>& a) noexcept : data_(a.data_) {}
constexpr T* allocate(size_type n) {
if (n > max_size())
throw std::bad_array_new_length();
return std::allocator<T>().allocate(n);
}
constexpr void deallocate(T* p, size_type n) noexcept { std::allocator<T>().deallocate(p, n); }
constexpr size_type max_size() const noexcept { return std::numeric_limits<size_type>::max() / sizeof(value_type); }
int get() { return data_; }
private:
int data_;
constexpr friend bool operator==(const CustomSizedAllocator& a, const CustomSizedAllocator& b) {
return a.data_ == b.data_;
}
constexpr friend bool operator!=(const CustomSizedAllocator& a, const CustomSizedAllocator& b) {
return a.data_ != b.data_;
}
};
int main() {
using Alloc = CustomSizedAllocator<bool, std::uint16_t, std::int16_t>;
std::vector<bool, Alloc> c{Alloc{1}};
c.resize(10);
return 0;
}
This code produces the following compilation error in libc++:
error: no matching function for call to 'max'
Root cause analysis
The root cause to the complication error is due to the following ambiguous std::max
call within vector<bool>
:
return std::max(2 * __cap, __align_it(__new_size)); |
In this context with the custom-sized allocator, the first operand's result type is int
due to integral promotion in the arithmetic involving int
and std::uint16_t
. Meanwhile, the second operand retains the size_type
type (i.e., std::uint16_t
). This type mismatch leads to a failure in template type argument deduction for std::max<T>
, resulting in the compilation error.
Proposed solution:
I've already submitted a PR #119801 to fix this issue. The solution is straightforward: explicitly specify the template type argument for std::max
to ensure consistent types for both operands.