CeresEngine 0.2.0
A game development framework
Loading...
Searching...
No Matches
SFINAE.hpp
Go to the documentation of this file.
1//
2// CeresEngine - A game development framework
3//
4// Created by Rogiel Sulzbach.
5// Copyright (c) 2018-2022 Rogiel Sulzbach. All rights reserved.
6//
7
8#pragma once
9
10#include "TypeTraits.hpp"
11
12#define CE_SFINAE_HAS_TYPE(NAME) \
13 template<typename, typename = void> struct has_type_##NAME : std::false_type {}; \
14 template<typename T> struct has_type_##NAME<T, std::void_t<typename T::NAME>> : std::true_type {};
15
16#define CE_SFINAE_HAS_METHOD(NAME) \
17 namespace internal { \
18 template<typename T, bool is_class = std::is_class<T>::value, typename = void> struct has_method_##NAME##_helper : std::false_type {}; \
19 \
20 template<typename T> struct has_method_##NAME##_helper<T, true, std::void_t<decltype(&T::NAME)>> : has_method_##NAME##_helper<decltype(&T::NAME)> {}; \
21 \
22 template<typename Signature> struct has_method_##NAME##_helper<Signature, false> { \
23 static_assert(std::is_member_function_pointer<Signature>::value, "Not a member function pointer"); \
24 using T = typename function_traits<Signature>::class_type; \
25 static_assert(!std::is_void<T>::value, "Void class type"); \
26 \
27 template<typename C, typename = std::void_t<decltype(static_cast<Signature>(&C::NAME))>> static auto check(int) -> std::true_type; \
28 template<typename> static auto check(...) -> std::false_type; \
29 \
30 using type = decltype(check<T>(0)); \
31 }; \
32 } \
33 template<typename Signature> struct has_method_##NAME : internal::has_method_##NAME##_helper<Signature>::type {};
34
35#define CE_SFINAE_CAN_CALL_METHOD(NAME) \
36 namespace internal { \
37 template<typename T, typename... Args> using result_of_call_method_##NAME = decltype(std::declval<T>().NAME(std::declval<Args>()...)); \
38 } \
39 template<typename T, typename Signature, typename = void> struct can_call_method_##NAME : std::false_type {}; \
40 template<typename T, typename... Args> \
41 struct can_call_method_##NAME<T, void(Args...), std::void_t<internal::result_of_call_method_##NAME<T, Args...>>> : std::true_type {}; \
42 template<typename T, typename R, typename... Args> \
43 struct can_call_method_##NAME<T, R(Args...), \
44 typename std::enable_if<!std::is_void<R>::value && std::is_convertible<internal::result_of_call_method_##NAME<T, Args...>, R>::value>::type> \
45 : std::true_type {};
46