Debugging metaprograms is not the easiest thing to know, but we still try.
To begin, remove the use of is_brackets_op_defined<float> and the declaration static void Check(...); . This will help us to see what the compiler did not like the overloaded version of Check ( code ).
main.cpp:19:30: error: no matching function for call to 'is_brackets_op_defined<int>::Check(Method<int>)' main.cpp:17:42: note: candidate: 'template<class C> static decltype (Method<C>::operator()) is_brackets_op_defined<T>::Check(const C&) [with C = C; T = int]' main.cpp:17:42: note: template argument deduction/substitution failed: main.cpp: In substitution of 'template<class C> static decltype (Method<T>::operator()) is_brackets_op_defined<int>::Check<C>(const C&) [with C = Method<int>]':
Well, as a C , the Method<int> comes to the Check function. Obviously, in this context, the Method<C>::operator() construct gives a compilation error for both int and float . And according to SFINAE, the compiler drops this overload.
We need to somehow change this enemy so that it unfolds into some type for int and gives substitution failed for float . In my opinion &C::operator() will be just right ( code ).
In principle, this can be stopped, but I cannot but suggest a bit to simplify the code. As return values, you can use std::true_type and std::false_type This allows you to throw out the use of std::is_same .
UPD. The question in the commentary suggested a second improvement. Instead of const C& you can use const C* . This will get rid of std::declval , which, for some reason, creates a compile error with incomplete type under GCC.
#include <iostream> #include <functional> template<typename T> struct Method; template<> struct Method<int> { int operator()() { return 1; } }; template<class T> struct is_brackets_op_defined { static std::false_type Check(...); template<typename C, class = decltype(&C::operator())> static std::true_type Check(const C*); using type = decltype(Check(static_cast<Method<T>*>(nullptr))); constexpr static bool value = type(); }; int main() { std::cout << std::boolalpha << is_brackets_op_defined<float>::value << std::endl; std::cout << std::boolalpha << is_brackets_op_defined<int>::value << std::endl; }
std::experimental::is_detected. - HolyBlackCatvoidversion and, as the compiler says, it becomes immediately clear what the error is. The author checks for the presence ofoperator ()inMethod<Method<T>>. In the checker, he managed to “wrap” everything twice in theMethodpattern. This is how it works: coliru.stacked-crooked.com/a/3058a2ba45ef597a - AnT