1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
#include <iostream>
#include <type_traits>
struct A {
void foo (int) const {}
void foo (int, bool, char) const {}
void foo() const {}
int foo (char, double) {return 0;}
bool foo (int) {return false;}
};
enum Constness {Const, NotConst};
template <typename R, Constness, typename... Args> struct F;
template <typename T, typename Void, typename... Fs>
struct Check : std::false_type {};
template <typename T, typename R, typename... Args, typename... Rest>
struct Check<T, typename std::enable_if<
std::is_same<R, decltype(std::declval<const T&>().foo(std::declval<Args>()...))>::value // Check if the return type is R, else inherit from std::false_type.
>::type, F<R, Const, Args...>, Rest...> : Check<T, void, Rest...> {}; // Check the next F. Will check the std::enable_if conditions in case the specializations are met.
template <typename T, typename R, typename... Args, typename... Rest>
struct Check<T, typename std::enable_if<
std::is_same<R, decltype(std::declval<T&>().foo(std::declval<Args>()...))>::value // Check if the return type is R, else inherit from std::false_type.
>::type, F<R, NotConst, Args...>, Rest...> : std::conditional<
Check<T, void, F<R, Const, Args...>>::value, // Check if foo is const. If so, inherit from std::false_type.
std::false_type,
Check<T, void, Rest...> // Check the next F. Will check the std::enable_if conditions in case the specializations are met.
>::type {};
template <typename T>
struct Check<T, void> : std::true_type {}; // Reached only when all the previous checks passed.
template <typename T, typename... Fs>
using CheckFooOverloads = Check<T, void, Fs...>; // Will check the std::enable_if conditions in case the specializations are met.
int main() {
std::cout << std::boolalpha << CheckFooOverloads<A, F<void, Const, int>, F<void, Const, int, bool, char>>::value << '\n'; // true, because void A::foo(int) const and void A::foo(int, bool, char) const overloads exist.
std::cout << CheckFooOverloads<A, F<void, Const, int>, F<void, Const, int, bool, char>, F<void, Const>>::value << '\n'; // true, because void A::foo(int) const, void A::foo(int, bool, char) const, and void A::foo() const overloads exist
std::cout << CheckFooOverloads<A, F<void, Const, int, bool>>::value << '\n'; // false, because no void A::foo(int, bool) const overload exists.
std::cout << CheckFooOverloads<A, F<void, Const, int, bool>, F<void, Const, int, bool, char, long, float>>::value << '\n'; // false
std::cout << CheckFooOverloads<A, F<void, Const, int>, F<void, Const, int, bool, char>, F<void, Const, int, bool, char, long, float>>::value << '\n'; // false (though the first two exist, the last does not).
std::cout << CheckFooOverloads<A, F<void, Const, int>, F<void, Const, int, bool, char>, F<void, Const, int, bool>>::value << '\n'; // false, because though void A::foo(int) const and void A::foo(int, bool, char) const overloads exist, no void A::foo(int, bool) const overload exists.
std::cout << CheckFooOverloads<A, F<int, NotConst, char, double>>::value << '\n'; // true, because int A::foo(char, double) exists (and is not const).
std::cout << CheckFooOverloads<A, F<int, NotConst, char, double>, F<bool, NotConst, int>>::value << '\n'; // true, because int A::foo(char, double) and bool A::foo(int) overloads exist.
std::cout << CheckFooOverloads<A, F<int, NotConst, char, double>, F<bool, NotConst, int>, F<void, Const, int, bool, char>>::value << '\n'; // true
std::cout << CheckFooOverloads<A, F<int, NotConst, char, double>, F<void, Const, int>, F<bool, NotConst, int>, F<void, Const, int, bool, char>>::value << '\n'; // true
std::cout << CheckFooOverloads<A, F<void, Const>, F<int, NotConst, char, double>, F<void, Const, int>, F<bool, NotConst, int>, F<void, Const, int, bool, char>>::value << '\n'; // true
std::cout << CheckFooOverloads<A, F<void, NotConst>>::value << '\n'; // false, because though void A::foo() const exists, void A::foo() does not.
std::cout << CheckFooOverloads<A, F<void, NotConst>, F<bool, Const, int>>::value << '\n'; // false
std::cout << CheckFooOverloads<A, F<void, NotConst>, F<int, NotConst, char, double>, F<void, Const, int>, F<bool, NotConst, int>, F<void, Const, int, bool, char>>::value << '\n'; // false
}
|