The following code demonstrates the core of the C ++ template metaprogramming pattern that I used to determine if type T instance of a particular class pattern:
#include <iostream> template<class A, class B> struct S{}; template<class A, class B> constexpr bool isS(const S<A,B>*) {return true;} template<class T> constexpr bool isS(const T*) {return false;} int main() { S<int,char> s; std::cout<<isS(&s)<<std::endl; return 0; }
It contains two overloads of the constexpr isS function template and outputs 1 , as expected. If I remove the pointer from the second isS , i.e. Replace it with
template<class T> constexpr bool isS(const T) {return false;}
the program unexpectedly displays 0 . If both versions of isS go into the compilation phase with overloading, the output means that the compiler chooses the second overload. I tested this under GCC, Clang, and vC ++ using the online compilers here , and they all give the same result. Why is this happening?
I read Herb Sutter's article โWhy not specialize function templatesโ several times, and it seems that both isS functions should be considered basic templates. If so, then we are talking about which one is the most specialized. Following intuition and this answer , I would expect the first isS be the most specialized, because T can correspond to each instance of S<A,B>* , and there are many possible instances of T that cannot correspond to S<A,B>* . I would like to find a paragraph in a working draft that defines this behavior, but I'm not quite sure which stage of compilation is causing the problem. Is this somehow related to "14.8.2.4 Subtracting template arguments during partial ordering"?
This problem is especially surprising given that the following code, in which the first isS accepts a reference to const S<A,B> , and the second accepts const T , outputs the expected value 1 :
#include <iostream> template<class A, class B> struct S{}; template<class A, class B> constexpr bool isS(const S<A,B>&) {return true;} template<class T> constexpr bool isS(const T) {return false;} int main() { S<int,char> s; std::cout<<isS(s)<<std::endl; return 0; }
So the problem seems to be related to the way pointers are handled.