Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SFINAE to check the existence of operators (without decltype)

I am trying to do an old project of my school, which deals with metaprogramming in C++98. The part I'm struggling against is about SFINAE.

The subject says I'm supposed to check if operator<< works between a stream object and another object by the use of a struct like this :

template<typename Stream, typename Object>
struct IsPrintable;

It says I should write a weird line with "two null references", I guess it should look like this :

sizeof(*(static_cast<Stream *>(NULL)) << *(static_cast<Object *>(NULL)))

It works when the operator is supported, but doesn't compile when it isn't. I can't figure out where I fail, here is the file :

template<typename Flux, typename Object>                                                                                                                                                                                                       
struct IsPrintable
{
  typedef char yes[1];
  typedef char no[2];

  template<size_t N>
  struct Test
  {
    typedef size_t type;
  };  

  template<typename U>
  static yes &isPrintable(U * = 0); 

  template<typename>
  static no &isPrintable(...);

  static const bool value = sizeof(isPrintable<Test<sizeof(*(static_cast<Flux *>(NULL)) << *(static_cast<Object *>(NULL)))> >(0)) == sizeof(yes);

};

The subject says explicitly to use a class taking a size_t as a parameter, and that the isPrintable method should take a NULL pointer to this class instance. Plus, the ugly expressions with static_cast should be used for a type definition, I tried to typedef it but the compiler screamed at me.

I don't get everything since I'm very new to this, I know there is some way to simplify that with the decltype operator, but the aim of the project is to do it in C++98, and it could be useful if I find some code of that type later on.

like image 872
Dante Avatar asked Jan 10 '23 16:01

Dante


2 Answers

#include <cstddef>

template<typename Flux, typename Object>                                                                                                                                                                                                       
struct IsPrintable
{
    typedef char yes[1];
    typedef char no[2];

    template <std::size_t N>
    struct SFINAE {};

    template <typename F, typename O>
    static yes& isPrintable(SFINAE<sizeof( *static_cast<F*>(NULL) << *static_cast<O*>(NULL) )>* = 0); 

    template <typename F, typename O>
    static no& isPrintable(...);

    static const bool value = sizeof(isPrintable<Flux, Object>(NULL)) == sizeof(yes);
};

DEMO

like image 69
Piotr Skotnicki Avatar answered Jan 27 '23 14:01

Piotr Skotnicki


template <typename Flux, typename Object>
struct IsPrintable
{
private:
    typedef char yes[1];
    typedef char no[2];

    template <size_t N> struct Test
    {
        typedef size_t type;
    };

    template <typename U>
    static yes& isPrintable(Test<sizeof(*(static_cast<Flux*>(NULL)) << *(static_cast<U*>(NULL)))>* = 0);

    template <typename> static no& isPrintable(...);
public:
    static const bool value = sizeof(isPrintable<Object>(0)) == sizeof(yes);
};

Live example

like image 20
Jarod42 Avatar answered Jan 27 '23 13:01

Jarod42