admin管理员组

文章数量:1123509


#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.


#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.

Share Improve this question asked 16 hours ago Craig StonehamCraig Stoneham 311 silver badge4 bronze badges New contributor Craig Stoneham is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 1
  • Better version of MCVE: godbolt.org/z/xbnczj8Kn – Marek R Commented 16 hours ago
Add a comment  | 

2 Answers 2

Reset to default 5

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

allocate<Allocator, T, Args...>(0) cannot match template <typename> static std::false_type allocate(...);

You just need the extra template parameters:

template <typename, typename, typename...>
static std::false_type allocate(...);

Demo

but requires from C++20 would have simpler syntax.

本文标签: Check for the existence of a template function in cStack Overflow