我应该注意一些编译器标志吗?下面的代码可以正常工作,并且可以按照GCC和Clang的要求运行,但不适用于MSVC。是什么使std::allocator
的分配在这里如此不同?
#include <type_traits>
#include <memory>
template <typename T, typename = std::void_t<>>
constexpr bool declares_allocate = false;
template <typename T>
constexpr bool declares_allocate<T, std::void_t<decltype(&T::allocate)>> = true;
struct normal_struct {
auto allocate() -> void {}
};
template <typename T>
struct struct_template {
auto allocate() -> void {}
};
template <typename T>
class class_template_public {
public:
auto allocate() -> void {}
};
template <typename T>
class class_template_private {
private:
auto allocate() -> void {}
};
auto main() -> int {
auto allocator = std::allocator<float>();
auto memory = allocator.allocate(1024);
static_assert(declares_allocate<normal_struct>); // pass
static_assert(declares_allocate<struct_template<float>>); // pass
static_assert(declares_allocate<class_template_public<float>>); // pass
// static_assert(declares_allocate<class_template_private<float>>); // fails
static_assert(declares_allocate<std::allocator<float>>); // fails when compiled by MSVC but not Clang or GCC
allocator.deallocate(memory, 1024);
return 0;
}
取决于C ++标准实现,可以将std::allocator<T>::allocate
定义为:
T* allocate(size_type n, const void* hint = 0);
T* allocate(size_type n);
T* allocate(size_type n, const void* hint);
T* allocate(size_t n);
即,第二种实现使allocate
成为重载的成员函数。现在MSVC's standard library中使用了那个:
_NODISCARD __declspec(allocator) _Ty* allocate(_CRT_GUARDOVERFLOW const size_t _Count) {
return static_cast<_Ty*>(_Allocate<_New_alignof<_Ty>>(_Get_size_of_n<sizeof(_Ty)>(_Count)));
}
_CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS _NODISCARD __declspec(allocator) _Ty* allocate(
_CRT_GUARDOVERFLOW const size_t _Count, const void*) {
return allocate(_Count);
}
这种实现使&T::allocate
模棱两可,因此在替换期间被拒绝。