iammilind
iammilind

Reputation: 69988

Why SFINAE results in compiler error where it should have worked?

I was trying to implement a meta-program which finds if given pointer type is const or not. i.e.

Following is the code:

template<class TYPE>
struct is_const
{
  typedef char yes[3];
  template<typename T>
  struct Perform
  {
    static yes& check (const T*&);
    static char check (T*&);
  };  

  TYPE it; 
  enum { value = (sizeof(Perform<TYPE>::check(it)) == sizeof(yes)) };  
};

And the compiler error messages are:

In instantiation of ‘is_const<int*>’:
instantiated from here
error: no matching function for call to ‘is_const<int*>::Perform<int*>::check(int*&)’
note: candidates are: static char (& is_const<TYPE>::Perform<T>::check(const T*&))[3] [with T = int*, TYPE = int*]
note: static char is_const<TYPE>::Perform<T>::check(T*&) [with T = int*, TYPE = int*]

My focus has shifted to the error message. If you see the last line:

note: static char is_const<TYPE>::Perform<T>::check(T*&) [with T = int*, TYPE = int*]

If we really replace T = int* and TYPE = int* then it really should match the appropriate function (char check()). I am anxious to know that what is going wrong here.

Upvotes: 3

Views: 200

Answers (3)

Armen Tsirunyan
Armen Tsirunyan

Reputation: 133014

THere are two things wrong in your code.

First, the following

static yes& check (const T*&);
static char check (T*&);

must be changed to

static yes& check (const T&);
static char check (T&);

Ans second, the it member must be static

static TYPE it;

or, just pass ((TYPE)0) to your check function. No need of the member.

Upvotes: 1

Adam Maras
Adam Maras

Reputation: 26853

Here's your problem:

static yes& check (const T*&);
static char check (T*&);

When you instantiate is_const<int*>, your function definitions are expanded to:

static yes& check (const int**&);
static char check (int**&);

However, your temporary item (TYPE it) is of type int*, like you specified. You need to change your check function signatures to remove the pointer specifier, like so:

static yes& check (const T&);
static char check (T&);

Upvotes: 1

Kerrek SB
Kerrek SB

Reputation: 477060

Why so roundabout? How about a straight-forward trait class:

#include <functional>

template <typename T> struct is_const_ptr : std::false_type { };
template <typename T> struct is_const_ptr<const T *> : std::true_type { };

struct Foo {};

int main()
{
  std::cout << is_const_ptr<Foo*>::value << is_const_ptr<const Foo*>::value << std::endl;
}

Upvotes: 9

Related Questions