.
#include <iostream>
#include <type_traits>
using namespace std;
template<typename T>
struct MyClass{
void hello( void) {
hello(std::is_same<T,bool>());
}
void hello(std::true_type){
cout<<"hello only for bools"<<endl;
}
};
int main(int argc, char** argv){
MyClass<bool> myclass1;
myclass1.hello();
MyClass<float> myclass2;
//myclass2.hello(); //throws error as it should
return 0;
}
I wrote the above code after reading enable_if method specialization. I want the hello() method to exist only if template argument is bool and it works. However I am running into problems when I am trying to solve the same problem using enable_if. I have the following code. Any help is appreciated. If enable_if is not appropriate for this job, what is generally used?
#include <iostream>
#include <type_traits>
using namespace std;
template<typename T>
struct MyClass{
typename std::enable_if<std::is_same<T,bool>::value, void>::type
hello(void)
{
cout<<"hello only for bools"<<endl;
}
};
int main(int argc, char** argv){
MyClass<bool> myclass1;
myclass1.hello();
MyClass<float> myclass2;// compilation error. Don't know how to solve
//myclass2.hello(); //I want only this line to cause compilation error
return 0;
}
EDIT: I found the solution to my question in jpihl's answer at std::enable_if to conditionally compile a member function. But could anyone explain why the above doesn't work?
#include <iostream>
#include <type_traits>
using namespace std;
template<typename T>
struct MyClass{
template<class Q = T>
typename std::enable_if<std::is_same<Q, bool>::value, void>::type hello()
{
cout<<"hello only for bools"<<endl;
}
};
int main(int argc, char** argv){
MyClass<bool> myclass1;
myclass1.hello();
MyClass<float> myclass2;// throws errow. Don't know how to solve
myclass2.hello(); //
return 0;
}
Your first attempt with
enable_ifdoes not work because SFINAE applies in overload resolution of function (or member function) templates, where it will eliminate a specialization of the function template from the overload set when that specialization cannot compile.The member
hello, in your first attempt, is not a member function template. It has no template parameters. It is simply a member function of a class template.Its return type is formulated by an
enable_ifexpression that will provoke compilation failure if the class template parameterTis not instantiated asbool. This doesn't make the member function itself into a template. SFINAE has no application. Once you declareMyClass<float> myclass2, the specialization ofMyClass<T>and all its members is completely determined. The member functionhelloof that specialization must be instantiated, and withT=floatthe attempt to do so must fail to compile.In the second, successful attempt,
hellois a member function template (of a class template). It has a template parameter,Q, which by default is =T. So SFINAE applies and you can leverage it withenable_ifin the intended manner. You may declareMyClass<float> myclass2without error, because doing so does not force any instantiation of the template memberMyClass<float>::hello<Q>Since you have written only one overload of
hello, there is only one specialization of the member function template for any choice ofQ. WhenQ=bool, that single specialization survives andmyclass1.hello()will compile. WhenQ!=bool, SFINAE eliminates the that single specialization andmyclass2.hello()does not compile.To appeciate vividly how SFINAE in the second case is operating at instantation of the member function template, consider that:
is fine; while on the other hand:
does not compile.
Here is documentation of SFINAE