DawidPi
DawidPi

Reputation: 2365

C++ enable_if in class - different ways of destruction

I am developing an application for an embedded device and therefore I do not have type_traits and enable_if (poor compiler quality). I created them on my own:

template <typename T>
struct is_pointer_t{
    enum{value = false};
};

template <typename T>
struct is_pointer_t<T*>{
    enum{value = true};
};

and simillar declarations for consts and volatiles.

Now implementation of enable_if:

template <bool boolean, typename T = void>
struct enable_if{};

template <typename T>
struct enable_if<true, T>{
    typedef T type;
};

Now I want to have a class, that depeneding on wheather I use pointers or normal types it calls destructor on them or not, so it would be great if I could have templated destructor. But I do not know how to do this as I am just beginning to undestand template programming. Following attempts failed:

template <typename T>
class pointerOrNot{
public:

    template <typename U>
    void one();
};

template <typename T>
template <typename enable_if<is_pointer_t<T>::value>::type>
void pointerOrNot<T>::one(){
    std::cout << "Success1" << std::endl;
}

template <typename T>
template <typename enable_if<!is_pointer_t<T>::value>::type>
void pointerOrNot<T>::one(){
    std::cout << "Success2" << std::endl;
}

and it says it does not match definition. So I tried following:

template <typename T>
class pointerOrNot{
public:

    template <typename enable_if<is_pointer_t<T>::value>::type>
    void one();
    template <typename enable_if<!is_pointer_t<T>::value>::type>
    void one();
};

But then one of one() has empty type as template and compilation fails. How can I do this? Also is it possible to do this with destructor?

Upvotes: 0

Views: 374

Answers (1)

ead
ead

Reputation: 34326

First lets consider the following class for pointers:

template <typename T>
struct Introducer{

  void intro(){
    std::cout<<"I'm a pointer, I point to adress "<<mem<<std::endl;
  }

  T mem;
  Introducer(T m):mem(m){}
};

it works fine with pointers, but it also works with non-pointers:

  Introducer<int> i(10);
  i.intro();//just fine!

We would like to detect this misuse during the compile time, also we change Introducer to

template <typename T>
struct Introducer{

  typename enable_if<is_pointer_t<T>::value, void>::type //this is the return type of the function
  intro(){
    std::cout<<"I'm a pointer, I point to adress "<<mem<<std::endl;
  }

  ...
};

Now compiler does not allow us to use non-pointer with Introducer. In the next step we would like to have a special function for non-pointers by means of SFINAE:

template <typename T>
struct Introducer{
  typename enable_if<is_pointer_t<T>::value, void>::type 
  intro(){
    std::cout<<"I'm a pointer, I point to adress "<<mem<<std::endl;
  }

  typename enable_if<!is_pointer_t<T>::value, void>::type 
  intro(){
    std::cout<<"I'm a non-pointer, my value is "<<mem<<std::endl;
  }

  ...
};

Hell, it does not even compile! Lets read the passage about SFINAE more carefully:

If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments. Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure.

T is not in the immediate context and thus SFINAE doesn't work, lets bring T into the immediate context:

template <typename T>
struct Introducer{

  template <typename C=T>
  typename enable_if<is_pointer_t<C>::value, void>::type 
  intro(){
    std::cout<<"I'm a pointer, I point to adress "<<mem<<std::endl;
  }


  template <typename C=T>
  typename enable_if<!is_pointer_t<C>::value, void>::type 
  intro(){
    std::cout<<"I'm a non-pointer, my value is "<<mem<<std::endl;
  }

  ...
};

now the program

int main(){
  Introducer<float*> fp(NULL);
  fp.intro();

  //But this works also:
  Introducer<int> i(10);
  i.intro();
}

results in:

I'm a pointer, I point to adress 0
I'm a non-pointer, my value is 10

What about the destructor? The easiest way would be to call a SFINAE-destruction-function from the destructor (I never saw a SFINAE-destructor and would not know how to write one, but this doesn't mean anything):

template <typename T>
struct Introducer{
  ...

    ~Introducer(){
    intro();
    std::cout<<"and I'm deleted..."<<std::endl;
  }
};

Upvotes: 1

Related Questions