#include <type_traits>
template <typename Allocator>
struct AllocatorTraits {
private:
template <typename U>
static auto malloc(int) -> decltype(static_cast<void* (U::*)(size_t)>(&U::malloc), std::true_type());
template <typename>
static std::false_type malloc(...);
template <typename U, typename T, typename... Args>
static auto allocate(int) -> decltype(static_cast<T* (U::*)(Args...)>(&U::template allocate<T, Args...>), std::true_type());
template <typename>
static std::false_type allocate(...);
public:
static constexpr bool has_malloc = decltype(malloc<Allocator>(0))::value;
template <typename T, typename... Args>
static constexpr bool has_allocate = decltype(allocate<Allocator, T, Args...>(0))::value;
};
class TestClass {
public:
void* malloc(size_t size) noexcept { return nullptr; }
template <typename T, typename ...Args>
T* allocate(Args &&...args) noexcept { return nullptr; }
};
static constexpr bool test_malloc = AllocatorTraits<TestClass>::has_malloc;
static constexpr bool test_allocate = AllocatorTraits<TestClass>::has_allocate<int>;
I am using C++20. This works fine if I comment the non template TestClass functions, so commenting out TestClass::malloc, will result in test_malloc being false. This will not compile if I comment out the template function
TestClass::allocate (error C2672: 'AllocatorTraits<TestClass>::allocate': no matching overloaded function found).
Can anybody help me to get this to work as expected please.
Since you can use C++20 just define a concept. They are more handy then trying using SFINAE.
#include <cstdint>
#include <type_traits>
#include <utility>
template <typename T, typename Ret, typename... Args>
concept has_allocate = requires(T x, Args... args) {
{ x.template allocate<Ret>(std::forward<Args>(args)...) } -> std::same_as<Ret*>;
};
class HasAllClass {
public:
void* malloc(std::size_t) noexcept { return nullptr; }
template <typename T, typename... Args>
T* allocate(Args&&...) noexcept { return nullptr; }
};
class Foo { };
static_assert(has_allocate<HasAllClass, int>);
static_assert(!has_allocate<Foo, int>);
https://godbolt.org/z/KaT6813s1
Your solution has simple problem. It should go like this:
template <typename, typename T, typename... Args>
static std::false_type allocate(...);
Note that you have omitted template parameters.
https://godbolt.org/z/T7x8jfox8