SFINAE construct problem

I'm trying to implement is_base template and I have "a little problem". Why this doesn't work as it's suppouse to?

#include <iostream>
using std::cout;
class Car
{
};

class Fiesta : public Car
{
};

template<class Base, class Derived>
struct isBase
{
    typedef char yes[2];
    typedef char no[1];

    template<class B, class D>
    static yes& f(D* d, B* b = d);

    template<class,class>
    static no&  f(...);

    static  bool type;
};




template<class Base, class Derived>
bool isBase<Base,Derived>::type = (sizeof(f<Base,Derived>(0,0)) == sizeof(yes));

int _tmain(int argc, _TCHAR* argv[])
{
    cout << isBase<Fiesta,Car>::type;//It should say false here but says true

    return 0;
}

Upvotes: 0

Views: 137

Answers (1)

GManNickG
GManNickG

Reputation: 504293

You're explicitly providing a value for the pointer: f<Base,Derived>(0, 0), no conversion needs to occur here, especially not a derived-to-base one; this test will always pass, as the first one is always callable (any pointer can be null).

You want something like this:

template<class Base, class Derived>
struct isBase
{
    typedef char yes[2];
    typedef char no[1];

    template <class B>
    static yes& f(B*);

    template <class>
    static no&  f(...);

    // (1) make it const (as it should be) and just define it inline
    // (2) it's not a type, it's a value; name appropriately
    static const bool value = sizeof(f<Base>((Derived*)0)) == sizeof(yes);
};

// use a standard signature for main
int main() // if you don't need the arguments, don't list them
{
    cout << isBase<Fiesta, Car>::value;
    cout << isBase<Car, Fiesta>::value;

   // return 0 is implicit for main, helpful for snippets
}

The first overload will be called if the pointer type is or can be converted to a Base*. So we make a pointer of the type Derived*, and if it actually is a derived class the conversion will work and the first overload is called; otherwise, the second.

Upvotes: 2

Related Questions