The book C++ Programming Language(fourth edition). Chapter 28.4 (page 796) explains enable_if and gives an example of making the definition of operator->() conditional. The example in the book is only a code snippet, and I completed it to a program as follows:
#include <iostream>
#include <type_traits>
#include <complex>
using namespace std;
template<bool B, typename T>
using Enable_if=typename std::enable_if<B,T>::type;
template<typename T>
constexpr bool Is_class(){ //the book example misses constexpr
return std::is_class<T>::value;
}
template<typename T>
class Smart_pointer{
public:
Smart_pointer(T* p):data(p){
}
T& operator*();
Enable_if<Is_class<T>(),T>* operator->(){
return data;
}
~Smart_pointer(){
delete data;
}
private:
T* data;
};
int main()
{
Smart_pointer<double> p(new double); //compiling error in g++ 4.7.2: no type named 'type' in 'struct std::enable_if<false, double>'
//Smart_pointer<std::complex<double>> q(new std::complex<double>);//compile successfully.
}
The code above doesn't compile in gcc 4.7.2. The compiler complains: error: no type named 'type' in 'struct std::enable_if'
According to the explanation in the book, the operator->() will be ignored if T is not a class. However, that doesn't explain the compiling error. The compiling error indicates the opposite, the definition of operator->() is not ignored even if T is not a class. The compiling error seems to be explained by this post std::enable_if to conditionally compile a member function . But the post seems inconsistent with the book explanation. Anyone can help and explain the usage of the enable_if for member function? In the above example, if I do want to define the operator->() only when T is class, is there a clean and elegant solution? Thank you.
Thank you very much for the replies. There is another workaround based on overloading(I wouldn't say it's better than other posted solutions)
template<typename T>
T* Smart_pointer<T>::operator->(){
op_arrow(std::integral_constant<bool,Is_class<T>()>());
}
private:
T* op_arrow(std::true_type){
return data;
}
T* op_arrow(std::false_type);