Reputation: 2365
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
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