MSV C не может скомпилировать проверки SFINAE - PullRequest
0 голосов
/ 16 июня 2020

Есть ли какой-нибудь флаг компилятора, о котором мне следует знать? Следующий код работает нормально и соответствует требованиям G CC и Clang, но не MSV C. Что отличает распределение 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;

}

https://godbolt.org/z/GVyNQZ

1 Ответ

2 голосов
/ 16 июня 2020

В зависимости от стандартной реализации C ++, std::allocator<T>::allocate можно определить как:


T* allocate(size_t n, const void* hint = 0);

T* allocate(size_t n);
T* allocate(size_t n, const void* hint); // deprecating usage of hint

T* allocate(size_t n);

То есть второй реализация превращает allocate в перегруженную функцию-член. И этот в настоящее время используется в стандартной библиотеке MSV C. :

_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 неоднозначным и поэтому отклоняется при замене.

...